Sorting in XSLT
by Bob DuCharme
|
Pages: 1, 2, 3, 4
All the examples so far have sorted the children (the employee elements) of an element (employees) using one or more child nodes of those children (the salary, first, and last elements or the hireDate attribute) as sort keys. The previous example's use of the hireDate attribute showed that the expression used as the xsl:sort element's select attribute doesn't have to be a child element name, but can be an attribute name instead, or even a value returned by a function.
Your sort key can be an even more complex XPath expression. For example, the next stylesheet sorts the wine elements in this document's winelist element, but not by a child of the wine element; it sorts the wine elements by a grandchild of the wine elements: the prices child's discounted element.
<winelist>
<wine grape="Chardonnay">
<winery>Lindeman's</winery>
<product>Bin 65</product>
<year>1998</year>
<prices>
<list>6.99</list>
<discounted>5.99</discounted>
<case>71.50</case>
</prices>
</wine>
<wine grape="Chardonnay">
<winery>Benziger</winery>
<product>Carneros</product>
<year>1997</year>
<prices>
<list>10.99</list>
<discounted>9.50</discounted>
<case>114.00</case>
</prices>
</wine>
<wine grape="Cabernet">
<winery>Duckpond</winery>
<product>Merit Selection</product>
<year>1996</year>
<prices>
<list>13.99</list>
<discounted>11.99</discounted>
<case>143.50</case>
</prices>
</wine>
<wine grape="Chardonnay">
<winery>Kendall Jackson</winery>
<product>Vintner's Reserve</product>
<year>1998</year>
<prices>
<list>12.50</list>
<discounted>9.99</discounted>
<case>115.00</case>
</prices>
</wine>
</winelist>
The sort key is only slightly more complicated than those shown in the earlier examples. It's an XPath expression saying "the discounted child of the prices element".
<!-- xq437.xsl: converts xq436.xml into xq438.xml -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="winelist">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="number" select="prices/discounted"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The entire stylesheet is not very big. It just copies the wine elements, sorted according to the sort key:
<?xml version="1.0" encoding="UTF-8"?>
<winelist>
<wine>
<winery>Lindeman's</winery>
<product>Bin 65</product>
<year>1998</year>
<prices>
<list>6.99</list>
<discounted>5.99</discounted>
<case>71.50</case>
</prices>
</wine><wine>
<winery>Benziger</winery>
<product>Carneros</product>
<year>1997</year>
<prices>
<list>10.99</list>
<discounted>9.50</discounted>
<case>114.00</case>
</prices>
</wine><wine>
<winery>Kendall Jackson</winery>
<product>Vintner's Reserve</product>
<year>1998</year>
<prices>
<list>12.50</list>
<discounted>9.99</discounted>
<case>115.00</case>
</prices>
</wine><wine>
<winery>Duckpond</winery>
<product>Merit Selection</product>
<year>1996</year>
<prices>
<list>13.99</list>
<discounted>11.99</discounted>
<case>143.50</case>
</prices>
</wine></winelist>