XSLT嵌套排序实现XML p节点按文本及number元素数值排序咨询
问题原因
你编写的代码存在两处核心逻辑错误:
- 排序嵌套逻辑无效:
<xsl:for-each select=".//p">已经将节点集遍历到单个p元素,此时在内部对单个节点调用<xsl:apply-templates>时加排序规则没有任何作用,排序仅对节点集合生效。 - 未兼容无number的标题节点:同分组下的标题p节点没有number子元素,需要保证这类节点排在同分组的最前面。
正确实现方案
以下提供XSLT 1.0兼容版本的实现,可直接运行得到预期结果:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 匹配livre根节点,输出新的livre容器 --> <xsl:template match="livre"> <livre> <!-- 对所有p节点按优先级排序 --> <xsl:apply-templates select="p"> <!-- 第一优先级:按第一个number前的文本前缀字典序排序 --> <xsl:sort select="substring-before(., string(number[1]))" data-type="text" order="ascending"/> <!-- 第二优先级:按第一个number的数值升序排序,无number的节点值为空默认排最前 --> <xsl:sort select="number[1]" data-type="number" order="ascending"/> <!-- 第三优先级:按第二个number的数值升序排序 --> <xsl:sort select="number[2]" data-type="number" order="ascending"/> </xsl:apply-templates> </livre> </xsl:template> <!-- 原样复制p节点及其全部子内容 --> <xsl:template match="p"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet>
如果使用XSLT 2.0及以上版本,可以显式处理空值逻辑,可读性更强:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:template match="livre"> <livre> <xsl:apply-templates select="p"> <xsl:sort select="if (exists(number[1])) then substring-before(., string(number[1])) else normalize-space(substring-before(., ')')) || ')'" data-type="text" order="ascending"/> <xsl:sort select="if (exists(number[1])) then number(number[1]) else 0" data-type="number" order="ascending"/> <xsl:sort select="if (exists(number[2])) then number(number[2]) else 0" data-type="number" order="ascending"/> </xsl:apply-templates> </livre> </xsl:template> <xsl:template match="p"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者Maria
相关产品推荐
相关产品推荐

