Chapter 63: XSLT

1. What does <xsl:sort> really do?

<xsl:sort> is the only built-in way in XSLT to sort a list of nodes before processing them.

It can only be used inside these two elements:

  • <xsl:for-each>
  • <xsl:apply-templates>

When you put one or more <xsl:sort> instructions as the first children of these elements, the processor will reorder the selected nodes before executing the loop/template on them.

Very important facts from the very beginning:

  • <xsl:sort>must be the first child inside <xsl:for-each> or <xsl:apply-templates> → anything before it is invalid
  • You can have multiple <xsl:sort> one after another (multi-level sort)
  • Sorting happens before the loop/template body is executed
  • The original input order is lost — the nodes are processed in the sorted order

2. Basic syntax – the pattern you will see 95% of the time

XML

or with <xsl:apply-templates> (more elegant style):

XML

3. The most important attributes of <xsl:sort>

Attribute Meaning / Possible values Default value Most common real usage Required?
select XPath expression that returns the sort key . (current node text) name, price, @date, substring(title,1,1) Yes
order ascending or descending ascending descending for newest-first, highest-price-first No
data-type text or number text number for prices, quantities, years No
case-order upper-first or lower-first upper-first lower-first for case-insensitive sort No
lang Language code for collation (sorting rules) system default en, de, fr… No
collation (XSLT 2.0+) URI of custom collation rules Very rare in XSLT 1.0 No

4. Step-by-step examples – from simple to realistic

Example 1 – Sort product names alphabetically

Input XML

XML

XSLT

XML

Output

HTML

Example 2 – Sort products by price (numeric!)

Important: without data-type=”number”, “1499” < “349” (string comparison!)

XML

Output

HTML

Example 3 – Multi-level sort (first by category, then by name)

XML

Output

HTML

Example 4 – Sort descending by stock (most stocked first)

XML

Output

HTML

Example 5 – Sort by first letter of title (case-insensitive)

XML

→ sorts ignoring case (A,a → same group)

Lesson 5 – Common beginner mistakes & how to avoid them

Mistake 1 Putting <xsl:sort> after other content

XML

Fix — <xsl:sort> must be the first child

Mistake 2 Forgetting data-type=”number” when sorting numbers

XML

Fix

XML

Mistake 3 Sorting inside <xsl:template> without <xsl:for-each> or <xsl:apply-templates>

XML

Fix — <xsl:sort> is only allowed inside for-each or apply-templates

Lesson 6 – Try yourself exercises (do these!)

  1. List all products sorted alphabetically by name
  2. Show products sorted by price ascending (use data-type=”number”)
  3. Show products sorted by stock descending (most stocked first)
  4. Sort books first by category ascending, then by title ascending
  5. Create a numbered list sorted by price descending
  6. Sort case-insensitively by title (hint: translate())

Summary – <xsl:sort> Quick Reference

Feature / Question Answer / Pattern Important note / trap
Basic syntax <xsl:sort select=”name”/> Must be first child inside for-each or apply-templates
Sort by text <xsl:sort select=”name”/> Default data-type=”text”
Sort by number <xsl:sort select=”price” data-type=”number”/> Without number, 1499 < 349 !
Descending order order=”descending” Default is ascending
Multi-level sort Multiple <xsl:sort> one after another First <xsl:sort> is primary key
Case-insensitive sort translate(…, ‘ABC…’, ‘abc…’) Very common need

Would you like to continue with one of these next?

  • Multi-level / multi-criteria sorting (category → name → price)
  • Sorting by calculated value (price after tax, name length…)
  • Sorting with xsl:apply-templates vs xsl:for-each
  • Case-insensitive & locale-aware sorting
  • Real-world patterns — invoice lines by amount, products by category, report rows by date
  • Debugging when sorting gives unexpected order

Just tell me which direction feels most useful or interesting for you right now! 😊

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *