Chapter 66: XSLT Apply
1. What does <xsl:apply-templates> really do?
<xsl:apply-templates> is the most important instruction in XSLT after <xsl:template> itself.
It tells the processor:
“Now take these nodes (selected by the select attribute) and process each one of them using the best matching template you can find.”
In other words:
- It is the “continue processing my children” command
- It is the mechanism that makes XSLT recursive and template-driven
- It is what creates the push-style (also called template-driven or event-driven) programming model of XSLT
Everyday analogy
Imagine you are cooking a big meal and you have several assistants (the templates).
You are currently preparing the main dish.
At some point you say:
“Someone please handle all the vegetables now.”
→ <xsl:apply-templates select=”vegetables”/>
Then each vegetable (carrot, potato, onion…) looks for the assistant (template) that knows how to handle that kind of vegetable.
- Carrot → “I know how to peel and chop carrots” → runs that template
- Potato → “I know how to boil potatoes” → runs another template
<xsl:apply-templates> is you delegating the work to the right specialists.
2. Basic syntax – the two most common patterns
Pattern A – No select attribute (process all children)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<xsl:template match="book"> <div class="book"> <h2><xsl:value-of select="title"/></h2> <!-- Process all children of this book using their own templates --> <xsl:apply-templates/> <p>Price: ₹<xsl:value-of select="price"/></p> </div> </xsl:template> |
→ the processor will automatically process every child node of <book> (title, author, price, etc.)
Pattern B – With select attribute (process specific children)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<xsl:template match="catalog"> <div class="catalog"> <h1>Products</h1> <!-- Only process <product> children, ignore everything else --> <xsl:apply-templates select="product"/> </div> </xsl:template> |
Very important difference
- <xsl:apply-templates/> → process all children in document order
- <xsl:apply-templates select=”…”/> → process only the nodes that match the expression (in document order)
3. Visual example – how the processor walks the tree
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 rules
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<xsl:template match="catalog"> <ul> <xsl:apply-templates select="product"/> <!-- only products --> </ul> </xsl:template> <xsl:template match="product"> <li> <strong><xsl:value-of select="name"/></strong> <xsl:apply-templates select="price"/> <!-- only price children --> </li> </xsl:template> <xsl:template match="price"> – ₹<xsl:value-of select="."/> </xsl:template> |
Step-by-step what happens
- Processor starts at root → finds match=”/catalog” template
- Outputs <ul>
- Sees <xsl:apply-templates select=”product”/> → finds all <product> children → processes first product → finds match=”product” template → outputs <li><strong>Wireless Mouse</strong> → sees <xsl:apply-templates select=”price”/> → finds the <price> child → processes it → outputs – ₹1499.00 → finishes the <li> → processes second product → same steps
- Finishes the <ul>
Result
|
0 1 2 3 4 5 6 7 8 9 |
<ul> <li><strong>Wireless Mouse</strong> – ₹1499.00</li> <li><strong>USB-C Hub</strong> – ₹2499.00</li> </ul> |
4. Real example: Product catalog with conditional stock message
|
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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes" encoding="UTF-8"/> <!-- Root template --> <xsl:template match="/"> <html> <head> <title>Product Catalog</title> <style> .product { margin:16px 0; padding:16px; border:1px solid #d1d5db; border-radius:8px; } .low-stock { color:#dc2626; font-weight:bold; } </style> </head> <body> <h1>Current Products</h1> <xsl:apply-templates select="catalog/product"/> </body> </html> </xsl:template> <!-- Template for each product --> <xsl:template match="product"> <div class="product"> <h3><xsl:value-of select="name"/></h3> <p> Price: ₹<xsl:value-of select="price"/> <xsl:if test="price/@currency"> <xsl:text> </xsl:text><xsl:value-of select="price/@currency"/> </xsl:if> </p> <!-- Delegate stock handling to its own template --> <xsl:apply-templates select="stock"/> </div> </xsl:template> <!-- Special template just for stock --> <xsl:template match="stock"> <p> Stock: <xsl:value-of select="."/> <xsl:if test=". &lt; 20"> <span class="low-stock"> (Low stock!)</span> </xsl:if> </p> </xsl:template> </xsl:stylesheet> |
Result (for stock=12)
|
0 1 2 3 4 5 6 7 8 9 10 |
<div class="product"> <h3>USB-C Hub</h3> <p>Price: ₹2499.00 INR</p> <p>Stock: 12 <span class="low-stock"> (Low stock!)</span></p> </div> |
Lesson 5 – Common beginner mistakes & how to avoid them
Mistake 1 Forgetting <xsl:apply-templates> → children are ignored
|
0 1 2 3 4 5 6 7 8 9 |
<xsl:template match="book"> <div><xsl:value-of select="title"/></div> <!-- forgot apply-templates → author, price, etc. are never processed --> </xsl:template> |
Fix Add <xsl:apply-templates/> or <xsl:apply-templates select=”…”/>
Mistake 2 Using <xsl:for-each> when <xsl:apply-templates> is better
|
0 1 2 3 4 5 6 7 8 |
<xsl:for-each select="product"> <div><xsl:value-of select="name"/></div> </xsl:for-each> |
→ hard to reuse or override later
Better (more modular)
|
0 1 2 3 4 5 6 7 8 9 10 |
<xsl:apply-templates select="product"/> <xsl:template match="product"> <div><xsl:value-of select="name"/></div> </xsl:template> |
Mistake 3 Not understanding the context change
Inside <xsl:apply-templates select=”price”>, the current node becomes the <price> element.
|
0 1 2 3 4 5 6 7 |
<xsl:apply-templates select="price"/> <!-- inside price template, "name" would be empty --> |
Lesson 6 – Try yourself exercises (do these!)
- Make a simple bullet list of product names using <xsl:apply-templates>
- Show name + price with currency symbol
- Add a red “Low stock!” message if stock < 20 (in a separate template)
- Create a table using <xsl:apply-templates> for rows
- Show “Free shipping” only if price > 2000 (in its own template)
- Make a nested structure: catalog → products → details
Summary – <xsl:apply-templates> Quick Reference
| Question / Goal | Recommended pattern | Important note / trap |
|---|---|---|
| Process all children | <xsl:apply-templates/> | Processes everything — including text nodes |
| Process only specific children | <xsl:apply-templates select=”product”/> | Very common & powerful |
| Process children in different order | Use multiple <xsl:apply-templates> with different select | Order is controlled by you |
| Reuse same element in different contexts | Separate template with match=”product” | Templates are global — can be called from anywhere |
| Override behavior in subtree | More specific match wins (longer path = higher priority) | Very powerful feature |
| Skip processing children | Don’t write <xsl:apply-templates/> | Children are ignored unless processed elsewhere |
Would you like to continue with one of these next?
- <xsl:apply-templates> vs <xsl:for-each> – detailed comparison + when to choose which
- Priority & conflict resolution (which template wins?)
- Modes – <xsl:apply-templates mode=”pdf”/> (very powerful)
- Pushing vs pulling – push style (apply-templates) vs pull style (for-each/value-of)
- Real-world patterns — invoice lines, order items, report sections, hierarchical navigation
- Debugging when apply-templates “does nothing” or processes wrong nodes
Just tell me which direction feels most useful or interesting for you right now! 😊
