这是一个通用解决方案,适用于任意数量的不同名称的子代outerElement
以及它们之间的任何首选顺序:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pUncertainElName" select="'second'"/>
<xsl:param name="pOrderedNames" select="'|first|second|third|'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="outerElement">
<xsl:variable name="vrtfFirstPass">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<xsl:apply-templates select=
"self::*[not(*[name() = $pUncertainElName])
or
*[name()=$pUncertainElName and @missing-cause]]"
mode="missing"/>
</xsl:copy>
</xsl:variable>
<xsl:apply-templates select="ext:node-set($vrtfFirstPass)/*" mode="pass2"/>
</xsl:template>
<xsl:template match="*[@missing-cause]"/>
<xsl:template match="*" mode="missing">
<xsl:element name="{$pUncertainElName}">
<textElement>Some Text</textElement>
</xsl:element>
</xsl:template>
<xsl:template match="outerElement" mode="pass2">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="number" select=
"string-length(substring-before($pOrderedNames,
concat('|', name(), '|')
)
)"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下 XML 文档时:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second missing-cause="">
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
产生了想要的正确结果:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
当它应用于此 XML 文档时:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
再次产生所需的正确结果:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
最后,当对这个 XML 文档应用相同的转换时:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
再次产生同样想要的正确结果:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
请注意:
可以有任意数量的不同命名的孩子outerElement
(不仅仅是三个),并且他们的顺序可能无法提前知道。
例如:
鉴于此 XML 文档:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second missing-cause="">
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
<fourth>
<textElement>Some Text</textElement>
</fourth>
</outerElement>
</doc>
这个顺序:第四,第二,第三,第一
我们只需要替换:
<xsl:param name="pOrderedNames" select="'|first|second|third|'"/>
与:
<xsl:param name="pOrderedNames" select="'|fourth|second|third|first|'"/>
现在产生了新的想要的结果:
<doc>
<outerElement>
<fourth>
<textElement>Some Text</textElement>
</fourth>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
<first>
<textElement>Some Text</textElement>
</first>
</outerElement>
</doc>
说明:
这是一个两遍转换。
可能存在或不存在的元素的名称在外部/全局参数中指定$pUncertainElName
。为了便于解释,我们将此元素称为second
。
On the first pass, all children of outerElement
with the exception of second
that has the missing-cause
attribute, are copied "as-is". If the second
element was absent or had the missing-cause
attribute, we output a new child of outerElement
-- the exactly wanted second
element.
In the second pass we sort the children of the outerElement
produced in the first pass, according to their priority, as specified in another external/global parameter, named $pOrderedNames
(a name that is left of another name in this string, has higher priority)