Chapter 62: XSLT
1. What does <xsl:for-each> really do?
<xsl:for-each> is the classic loop in XSLT 1.0.
It lets you:
Take a set of nodes (selected by an XPath expression) and repeat the same block of output code once for each node in that set.
It is the XSLT equivalent of:
|
0 1 2 3 4 5 6 7 8 |
for (let item of items) { console.log(item.name); } |
or in Python:
|
0 1 2 3 4 5 6 7 |
for item in items: print(item["name"]) |
Very important mindset shift
In normal programming languages, you usually write:
|
0 1 2 3 4 5 6 7 8 |
for each product: print the name print the price |
In XSLT push style (the more elegant way), you prefer templates + apply-templates.
But sometimes you need exact control over the order or very simple flat repetition — and that’s when <xsl:for-each> is useful.
2. Basic syntax – the pattern you will see 95% of the time
|
0 1 2 3 4 5 6 7 8 9 10 11 |
<xsl:for-each select="XPath-expression"> <!-- everything inside here is repeated once for each selected node --> <li> <xsl:value-of select="name"/> </li> </xsl:for-each> |
- select=”…” → XPath expression that returns a node-set (list of nodes)
- For each node in that set:
- the current node becomes the context node inside the loop
- the block is executed once
3. Very first realistic example – simple list
Input XML
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<catalog> <product> <name>Wireless Mouse</name> <price>1499.00</price> </product> <product> <name>USB-C Hub</name> <price>2499.00</price> </product> </catalog> |
XSLT
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<xsl:template match="catalog"> <ul> <xsl:for-each select="product"> <li> <xsl:value-of select="name"/> – ₹<xsl:value-of select="price"/> </li> </xsl:for-each> </ul> </xsl:template> |
Result HTML
|
0 1 2 3 4 5 6 7 8 9 |
<ul> <li>Wireless Mouse – ₹1499.00</li> <li>USB-C Hub – ₹2499.00</li> </ul> |
Inside the loop:
- First time: current node = first <product>
- Second time: current node = second <product>
That’s why name and price refer to the current product each time.
4. Example 2 – Adding position number + conditional formatting
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<xsl:for-each select="product"> <tr> <!-- position() starts from 1 --> <td><xsl:value-of select="position()"/></td> <td><xsl:value-of select="name"/></td> <td> <xsl:choose> <xsl:when test="number(price) > 2000"> <strong style="color:#059669;"> <xsl:value-of select="price"/> </strong> </xsl:when> <xsl:otherwise> <xsl:value-of select="price"/> </xsl:otherwise> </xsl:choose> </td> </tr> </xsl:for-each> |
Result table rows
|
0 1 2 3 4 5 6 7 |
<tr><td>1</td><td>Wireless Mouse</td><td>1499.00</td></tr> <tr><td>2</td><td>USB-C Hub</td><td><strong style="color:#059669;">2499.00</strong></td></tr> |
5. Example 3 – Using <xsl:for-each> with sorting
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<xsl:for-each select="product"> <!-- sort by name ascending --> <xsl:sort select="name" order="ascending"/> <li> <xsl:value-of select="name"/> </li> </xsl:for-each> |
→ products will be listed in alphabetical order
Note: <xsl:sort> must be first child inside <xsl:for-each>
6. Example 4 – <xsl:for-each> vs <xsl:apply-templates> (very important comparison)
Pull style – for-each
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
<xsl:template match="catalog"> <ul> <xsl:for-each select="product"> <li><xsl:value-of select="name"/></li> </xsl:for-each> </ul> </xsl:template> |
Push style – apply-templates (usually preferred)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<xsl:template match="catalog"> <ul> <xsl:apply-templates select="product"/> </ul> </xsl:template> <xsl:template match="product"> <li><xsl:value-of select="name"/></li> </xsl:template> |
When to prefer <xsl:apply-templates> over <xsl:for-each>
- You want reusable rules for the same element type in different places
- You have nested structures (book → chapter → paragraph)
- You want to override behavior in different parts of the document
- You want the processor to automatically handle hierarchy
When to prefer <xsl:for-each>
- You need very strict control over order and layout
- You are building a flat list or table row
- You want to sort or group explicitly
- You are doing simple repetition without deep nesting
7. Common beginner mistakes & how to avoid them
Mistake 1 Forgetting that context changes inside the loop
|
0 1 2 3 4 5 6 7 8 |
<xsl:for-each select="product"> <xsl:value-of select="catalog/product/name"/> <!-- WRONG --> </xsl:for-each> |
Fix Inside the loop, the current product is the context:
|
0 1 2 3 4 5 6 |
<xsl:value-of select="name"/> |
Mistake 2 Trying to modify variables inside <xsl:for-each> (XSLT 1.0 doesn’t allow it)
XSLT 1.0 variables are immutable.
Fix (use XSLT 2.0/3.0 or rethink the logic)
Mistake 3 Expecting <xsl:for-each> to create a new scope like a function
No — the context node changes, but variables from outside are still visible.
8. Try yourself exercises (do these!)
- Create a numbered list of all product names using <xsl:for-each>
- Make a table row for each product with columns: Position | Name | Price
- Show “Low stock!” in red if stock < 20
- Sort products alphabetically by name
- Show only products where price > 1500
- Create a comma-separated list of all names
Summary – <xsl:for-each> Quick Reference
| Feature / Question | Answer / Pattern |
|---|---|
| Basic syntax | <xsl:for-each select=”products”> … </xsl:for-each> |
| Access current item | name, price, @currency (relative to current node) |
| Get position (1-based) | position() |
| Get total count | last() |
| Sort the loop | <xsl:sort select=”name”/> as first child |
| Prefer over for-each | <xsl:apply-templates select=”product”/> + separate template |
| When to use for-each | Flat lists, tables, strict order, sorting |
Would you like to continue with one of these next?
- <xsl:for-each> vs <xsl:apply-templates> – detailed comparison with examples
- Sorting inside <xsl:for-each> (multiple sort keys)
- Grouping with <xsl:for-each-group> (XSLT 2.0/3.0)
- Nested <xsl:for-each> – products → variants → options
- Real-world patterns — invoice lines, order items, report rows
- Debugging when for-each outputs nothing or wrong order
Just tell me which direction feels most useful or interesting for you right now! 😊
