使用xsl:sort排序时如何保留未排序元素的问题
问题:XSLT排序后丢失loops节点下的非loop元素
示例输入XML
<ns3:ASC858_004010 xmlns:ns3="http://sap.com"> <root> <name1/> <name2/> <loops> <name3/> <loop mode="2"> <counter>2</counter> </loop> <loop mode="1"> <counter>1</counter> </loop> <name4/> </loops> <name5/> </root> </ns3:ASC858_004010>
原XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="xml" indent="yes"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="loops"> <xsl:copy> <xsl:apply-templates select="loop"> <xsl:sort select="counter"/> </xsl:apply-templates> </xsl:copy> </xsl:template> </xsl:stylesheet>
当前输出结果
<ns3:ASC858_004010 xmlns:ns3="http://sap.com"> <root> <name1/> <name2/> <loops> <loop mode="1"> <counter>1</counter> </loop> <loop mode="2"> <counter>2</counter> </loop> </loops> <name5/> </root> </ns3:ASC858_004010>
期望输出结果
<ns3:ASC858_004010 xmlns:ns3="http://sap.com"> <root> <name1/> <name2/> <loops> <name3/> <loop mode="1"> <counter>1</counter> </loop> <loop mode="2"> <counter>2</counter> </loop> <name4/> </loops> <name5/> </root> </ns3:ASC858_004010>
错误原因
你的loops模板里仅对loop元素应用了模板,完全忽略了loops节点下的其他子元素(比如name3、name4),导致这些元素没有被复制到输出中。
修正后的XSLT代码
如果需要保留所有非loop元素的原始位置(name3在loop前、name4在loop后),可以分三步处理:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="xml" indent="yes"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="loops"> <xsl:copy> <!-- 处理所有在loop之前的非loop节点 --> <xsl:apply-templates select="node()[not(self::loop) and following-sibling::loop]"/> <!-- 排序处理loop元素,指定data-type确保数字排序准确 --> <xsl:apply-templates select="loop"> <xsl:sort select="counter" data-type="number"/> </xsl:apply-templates> <!-- 处理所有在loop之后的非loop节点 --> <xsl:apply-templates select="node()[not(self::loop) and preceding-sibling::loop]"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
如果不需要区分位置,只需要保留所有非loop元素,也可以简化为:
<xsl:template match="loops"> <xsl:copy> <!-- 先处理所有非loop子元素 --> <xsl:apply-templates select="*[not(self::loop)]"/> <!-- 再排序处理loop元素 --> <xsl:apply-templates select="loop"> <xsl:sort select="counter" data-type="number"/> </xsl:apply-templates> </xsl:copy> </xsl:template>
修正后的输出结果
<ns3:ASC858_004010 xmlns:ns3="http://sap.com"> <root> <name1/> <name2/> <loops> <name3/> <loop mode="1"> <counter>1</counter> </loop> <loop mode="2"> <counter>2</counter> </loop> <name4/> </loops> <name5/> </root> </ns3:ASC858_004010>
内容的提问来源于stack exchange,提问作者badbee
相关产品推荐
相关产品推荐

