XSLT提供了专门的排序机制,通过xsl:sort元素可以对XML文档中的节点按照指定规则进行排序,无需在应用层额外编写排序逻辑,能大幅提升XML转换的处理效率。

xsl:sort元素的基本用法
要在XSLT中实现节点排序,需要在xsl:for-each或者xsl:apply-templates指令内部添加xsl:sort元素,排序会在遍历节点前先执行。xsl:sort的常用属性包括select、order、data-type,下面通过示例说明。
首先准备一份待转换的XML文档,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book>
<title>XML入门教程</title>
<price>59.9</price>
<year>2020</year>
</book>
<book>
<title>XSLT实战指南</title>
<price>79.9</price>
<year>2022</year>
</book>
<book>
<title>前端开发进阶</title>
<price>69.9</price>
<year>2021</year>
</book>
</bookstore>
接下来编写XSLT样式表,按照书籍的出版年份升序排序输出书籍信息:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h3>按出版年份升序排列的书籍列表</h3>
<ul>
<!-- 遍历所有book节点,先按year子节点升序排序 -->
<xsl:for-each select="bookstore/book">
<xsl:sort select="year" order="ascending" data-type="number"/>
<li>
<strong>书名:</strong><xsl:value-of select="title"/>
<br/>
<strong>价格:</strong><xsl:value-of select="price"/>
<br/>
<strong>出版年份:</strong><xsl:value-of select="year"/>
</li>
</xsl:for-each>
</ul>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
xsl:sort常用属性说明
理解xsl:sort的属性是灵活使用排序功能的基础,各属性的作用如下:
- select:指定排序的依据,通常是节点的子元素或者属性,例如select="price"表示按照price子节点的值排序。
- order:指定排序顺序,可选值为ascending(升序,默认值)和descending(降序)。
- data-type:指定排序的数据类型,可选值为text(文本排序,默认值)和number(数值排序)。如果排序的值是数字,必须指定该属性为number,否则会按照文本规则排序,导致结果不符合预期。
- lang:指定排序使用的语言,主要用于文本排序时的本地化规则,比如不同语言的字母排序规则不同。
多条件排序实现
如果需要根据多个规则排序,可以在xsl:for-each或者xsl:apply-templates内部添加多个xsl:sort元素,排序优先级按照xsl:sort的出现顺序从高到低排列。
下面的示例实现先按价格降序排序,价格相同的再按出版年份升序排序:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h3>多条件排序的书籍列表</h3>
<ul>
<xsl:for-each select="bookstore/book">
<!-- 第一排序条件:价格降序 -->
<xsl:sort select="price" order="descending" data-type="number"/>
<!-- 第二排序条件:出版年份升序 -->
<xsl:sort select="year" order="ascending" data-type="number"/>
<li>
<strong>书名:</strong><xsl:value-of select="title"/>
<br/>
<strong>价格:</strong><xsl:value-of select="price"/>
<br/>
<strong>出版年份:</strong><xsl:value-of select="year"/>
</li>
</xsl:for-each>
</ul>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
按属性排序的场景
除了按照子元素排序,也可以按照节点的属性排序,只需要在select属性中指定属性路径即可。例如如果book节点有category属性,要按照category属性排序,写法为<xsl:sort select="@category"/>。
修改XML文档添加category属性:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="tech">
<title>XML入门教程</title>
<price>59.9</price>
</book>
<book category="literature">
<title>散文精选</title>
<price>49.9</price>
</book>
<book category="tech">
<title>XSLT实战指南</title>
<price>79.9</price>
</book>
</bookstore>
对应的XSLT排序代码为:
<xsl:for-each select="bookstore/book">
<xsl:sort select="@category" order="ascending"/>
<li><xsl:value-of select="title"/> - 分类:<xsl:value-of select="@category"/></li>
</xsl:for-each>
注意事项
- xsl:sort必须作为xsl:for-each或者xsl:apply-templates的第一个子元素,不能放在其他位置,否则不会生效。
- 排序是在XSLT处理器遍历节点前完成的,不会影响原始XML文档的结构,只会影响转换后的输出顺序。
- 如果select指定的节点不存在,该节点会被排到序列的最前面或者最后面,具体取决于处理器的实现,实际开发中要确保排序依据节点存在。