这是一个通用解决方案,适用于 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。
在第一次传递时,outerElement 的所有子级(具有 missing-cause 属性的 second 除外)都“按原样”复制。如果second 元素不存在或具有missing-cause 属性,我们将输出outerElement 的新子元素——正是想要的second 元素。
在第二遍中,我们根据在另一个名为 $pOrderedNames 的另一个外部/全局参数中指定的优先级,对第一遍中生成的 outerElement 的子级进行排序。此字符串中的另一个名称,具有更高的优先级)