Sponsored

XSLT Reference

xsl:sort

XSLT 1.0 element

Specifies a sort key for xsl:apply-templates or xsl:for-each, controlling the order in which nodes are processed.

Syntax
<xsl:sort select="expression" order="ascending|descending" data-type="text|number"/>

Description

xsl:sort is placed as an immediate child of xsl:apply-templates or xsl:for-each to define the sort order for node processing. It does not alter the source document; it only changes the sequence in which the processor visits the selected nodes.

Multiple xsl:sort elements can be nested to define compound sort keys: the first xsl:sort is the primary key, the second is the secondary key (used when the primary values are equal), and so on.

The select attribute is an XPath expression evaluated against each candidate node to produce its sort key. Omitting select defaults to the string value of the context node (equivalent to select="."). The data-type attribute controls whether comparison is lexicographic (text, the default) or numeric (number). When sorting numerically, the key is converted to a number; non-numeric strings sort as NaN, which typically appears first in ascending order.

Attributes

AttributeTypeRequiredDescription
selectXPath expressionNoSort key expression. Defaults to . (string value of context node).
orderascending / descendingNoSort direction. Default is ascending.
data-typetext / number / QNameNoComparison type. Default is text.
case-orderupper-first / lower-firstNoCase ordering for text comparisons. Processor-defined default.
langlanguage codeNoLanguage for locale-sensitive collation.

Examples

Sort by numeric attribute

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<products>
  <product price="24.99">Gadget</product>
  <product price="9.99">Widget</product>
  <product price="49.99">Device</product>
  <product price="4.49">Bolt</product>
</products>

Stylesheet:

<?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"/>

  <xsl:template match="/products">
    <sorted>
      <xsl:apply-templates select="product">
        <xsl:sort select="@price" data-type="number" order="ascending"/>
      </xsl:apply-templates>
    </sorted>
  </xsl:template>

  <xsl:template match="product">
    <item price="{@price}"><xsl:value-of select="."/></item>
  </xsl:template>
</xsl:stylesheet>

Output:

<sorted>
  <item price="4.49">Bolt</item>
  <item price="9.99">Widget</item>
  <item price="24.99">Gadget</item>
  <item price="49.99">Device</item>
</sorted>

Multi-key sort: last name then first name

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<people>
  <person first="Alice" last="Smith"/>
  <person first="Bob" last="Jones"/>
  <person first="Anna" last="Smith"/>
  <person first="Carol" last="Jones"/>
</people>

Stylesheet:

<?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"/>

  <xsl:template match="/people">
    <sorted>
      <xsl:for-each select="person">
        <xsl:sort select="@last"/>
        <xsl:sort select="@first"/>
        <person><xsl:value-of select="concat(@first, ' ', @last)"/></person>
      </xsl:for-each>
    </sorted>
  </xsl:template>
</xsl:stylesheet>

Output:

<sorted>
  <person>Bob Jones</person>
  <person>Carol Jones</person>
  <person>Alice Smith</person>
  <person>Anna Smith</person>
</sorted>

Notes

  • xsl:sort elements must appear before any other content inside xsl:for-each or xsl:apply-templates. Placing them after output instructions is a schema error.
  • When data-type="number", the sort key is converted to a floating-point number. Values that cannot be converted become NaN; in ascending order, NaN values typically sort before any numeric value, but this is implementation-defined.
  • Text sorting is locale-sensitive in theory, but XSLT 1.0 has limited collation support. Use the lang attribute or processor-specific collation URIs for reliable locale-aware sorting.
  • The position() function inside a sorted xsl:for-each reflects the sorted position, not the original document position.

See also