Sorting in XSLT
by Bob DuCharme
|
Pages: 1, 2, 3, 4
To reverse the order of this or any other sort, add an order attribute with a value of "descending":
<!-- xq428.xsl: converts xq423.xml into xq429.xml -->
<xsl:template match="employees">
<xsl:apply-templates>
<xsl:sort select="salary" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:template>
|
Related Reading
XML Schema |
Whether the data-type attribute has a value of "number" like the stylesheet above or "text" (the default), an order value of "descending" reverses the order of the sort:
Last: Hill
First: Phil
Salary: 100000
Hire Date: 04/23/1999
Last: Herbert
First: Johnny
Salary: 95000
Hire Date: 09/01/1998
Last: Hill
First: Graham
Salary: 89000
Hire Date: 08/20/2000
If your xsl:apply-templates (or xsl:for-each) element has more than one xsl:sort instruction inside of it, the XSLT processor treats them as multiple keys to the sort. For example, the stylesheet with this next template sorts the employees by last name and then by first name so that any employees with the same last name will be in first name order.
<!-- xq430.xsl: converts xq423.xml into xq431.xml -->
<xsl:template match="employees">
<xsl:apply-templates>
<xsl:sort select="last"/>
<xsl:sort select="first"/>
</xsl:apply-templates>
</xsl:template>
When applied to the document above, the result shows Johnny Herbert before Phil and Graham Hill, and the secondary sort puts Graham Hill before Phil Hill:
Last: Herbert
First: Johnny
Salary: 95000
Hire Date: 09/01/1998
Last: Hill
First: Graham
Salary: 89000
Hire Date: 08/20/2000
Last: Hill
First: Phil
Salary: 100000
Hire Date: 04/23/1999
The sort key doesn't need to be an element child of the sorted elements. The xsl:sort instruction's select attribute can take any XPath expression as a sort key. For example, the following version sorts the employees by their hireDate attribute values:
<!-- xq432.xsl: converts xq423.xml into xq433.xml -->
<xsl:template match="employees">
<xsl:apply-templates>
<xsl:sort select="@hireDate"/>
</xsl:apply-templates>
</xsl:template>
Treating the dates as strings doesn't do much good, because they're sorted alphabetically,
Last: Hill
First: Phil
Salary: 100000
Hire Date: 04/23/1999
Last: Hill
First: Graham
Salary: 89000
Hire Date: 08/20/2000
Last: Herbert
First: Johnny
Salary: 95000
Hire Date: 09/01/1998
but it's easy enough to have three sort keys based on the year, month, and day substrings of the date string:
<!-- xq434.xsl: converts xq423.xml into xq435.xml -->
<xsl:template match="employees">
<xsl:apply-templates>
<xsl:sort select="substring(@hireDate,7,4)"/> <!-- year -->
<xsl:sort select="substring(@hireDate,1,2)"/> <!-- month -->
<xsl:sort select="substring(@hireDate,3,2)"/> <!-- day -->
</xsl:apply-templates>
</xsl:template>
This stylesheet sorts the dates properly. (An important feature of XSLT 2.0 -- and, some say, the one that's going to slow its progress toward Recommendation status the most -- is the ability to handle typed data. Once in place, you'll be able to just say "this attribute is a date, so sort it that way.")
Last: Herbert
First: Johnny
Salary: 95000
Hire Date: 09/01/1998
Last: Hill
First: Phil
Salary: 100000
Hire Date: 04/23/1999
Last: Hill
First: Graham
Salary: 89000
Hire Date: 08/20/2000
