How Do You Iterate Nodes with xsl:for-each in XSLT?

This article examines how the <xsl:for-each> element processes node-sets in Extensible Stylesheet Language Transformations (XSLT). It explains how the processor evaluates the target node-set, manages context shifts during traversal, applies sorting rules, and constructs the resulting output tree.

The Mechanism of <xsl:for-each>

The <xsl:for-each> instruction directs an XSLT processor to iterate over a sequence of nodes selected by an XPath expression. Unlike imperative programming loops (such as for or while), which evaluate state changes sequentially across iterations, <xsl:for-each> acts as a declarative iteration pattern across an immutable node-set.

When the processor encounters <xsl:for-each select="expression">, it performs the following steps:

  1. Evaluation: The processor evaluates the XPath expression in the select attribute against the current context node to generate a node-set (or sequence in XSLT 2.0+).
  2. Context Establishment: The processor establishes a current node list containing all matched nodes, arranged by default in document order.
  3. Execution: The processor loops through the node list, applying the inner template body to each node individually.

Context Switching Inside the Loop

During each iteration of <xsl:for-each>, the processor automatically alters the evaluation context:

Example XML Source

<catalog>
  <book id="bk101">
    <title>XML Guide</title>
    <price>44.95</price>
  </book>
  <book id="bk102">
    <title>XPath Basics</title>
    <price>29.99</price>
  </book>
</catalog>

Example Transformation

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/catalog">
    <ul>
      <xsl:for-each select="book">
        <li>
          <xsl:value-of select="position()"/>: 
          <xsl:value-of select="title"/> - 
          $<xsl:value-of select="price"/>
        </li>
      </xsl:for-each>
    </ul>
  </xsl:template>
</xsl:stylesheet>

In this transformation, the expression select="book" yields a node-set containing both <book> elements. Within the loop body, select="title" and select="price" evaluate relative to each active <book> node rather than the root <catalog>.

Sorting Iteration Output

By default, <xsl:for-each> traverses nodes in document order. You can override this sequence by inserting one or more <xsl:sort> child elements immediately inside the <xsl:for-each> block before any template content.

<xsl:for-each select="book">
  <xsl:sort select="price" data-type="number" order="ascending"/>
  <li>
    <xsl:value-of select="title"/> (<xsl:value-of select="price"/>)
  </li>
</xsl:for-each>

When <xsl:sort> is present, the processor reorders the node list before beginning iteration. Consequently, position() reflects the sorted rank rather than the original document position.

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

While <xsl:for-each> provides a compact way to handle repetitive structures, it tightly couples template logic to a specific document hierarchy. In standard XSLT design, <xsl:apply-templates> is preferred for recursive or polymorphic XML structures, while <xsl:for-each> is best suited for tabular data rendering and straightforward, localized iterations.