Sorting in XSLT

Using XSLT we have a way of sorting a list of elements by the xsl:sort element.

The starting point is this XML file:

<?xml version="1.0" encoding="UTF-8"?>
<Objects>
<Object name="Car">
<Characteristic>Hard</Characteristic>
<Characteristic>Shiny</Characteristic>
<Characteristic>Has 4 wheels</Characteristic>
<Characteristic>Internal Combustion Engine</Characteristic>
</Object>
<Object name="Orange">
<Characteristic>Fruit</Characteristic>
<Characteristic>Juicy</Characteristic>
<Characteristic>Dimpled skin</Characteristic>
<Characteristic>Citrus</Characteristic>
</Object>
<Object name="Giraffe">
<Characteristic>Tall</Characteristic>
<Characteristic>Four legs</Characteristic>
<Characteristic>Big spots</Characteristic>
<Characteristic>Mammal</Characteristic>
</Object>
<Object name="Prawn Cracker">
<Characteristic>Crisp</Characteristic>
<Characteristic>Savoury</Characteristic>
<Characteristic>Off white</Characteristic>
<Characteristic>Edible</Characteristic>
</Object>
</Objects>

We want to generate an HTML where the Objects are ordered by ascending name, with each object having its Characteristic ordered by content in descending alphabetical order:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Object Characteristics</title>
</head>
<body>
<h3>Characteristics of Car</h3>
<ul>
<li>Shiny</li>
<li>Internal Combustion Engine</li>
<li>Has 4 wheels</li>
<li>Hard</li>
</ul>
<h3>Characteristics of Giraffe</h3>
<ul>
<li>Tall</li>
<li>Mammal</li>
<li>Four legs</li>
<li>Big spots</li>
</ul>
<h3>Characteristics of Orange</h3>
<ul>
<li>Juicy</li>
<li>Fruit</li>
<li>Dimpled skin</li>
<li>Citrus</li>
</ul>
<h3>Characteristics of Prawn Cracker</h3>
<ul>
<li>Savoury</li>
<li>Off white</li>
<li>Edible</li>
<li>Crisp</li>
</ul>
</body>
</html>

Here is the XSLT that we use:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
<html>
<head>
<title>Object Characteristics</title>
</head>
<body>
<xsl:apply-templates select="/Objects/Object">
<xsl:sort select="@name"/> <!-- 1 -->
</xsl:apply-templates>
</body>
</html>
</xsl:template>

<xsl:template match="Object">
<h3>Characteristics of <xsl:value-of select="@name"/></h3>
<ul>
<xsl:for-each select="Characteristic">
<xsl:sort select="." order="descending"/> <!-- 2 -->
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</xsl:template>

</xsl:stylesheet>

1. apply-templates this time is not an empty element, as it usually is, but it has a child xsl:sort element with specified as select attribute the value used for sorting. In this case we use the name attribute for the Object element. The xsl:sort element has another attribute, order, that is defaulted to ascending. Since we actually want to have the Object sorted by ascending name, we can avoid to use it.
2. inside xsl:template we use again xsl:sort, here as child of a xsl:for-each element. We specify that we work with the current value (using the dot notation) and that the order is descending.

More information on XSLT and Saxon in chapter eight of Beginning XML by David Hunter et al. (Wrox).

No comments:

Post a Comment