Chapter 65: XSLT
1. What is <xsl:choose> and why do we need it?
<xsl:choose> is the closest thing XSLT has to a full if/else-if/else statement.
Unlike <xsl:if>, which only has a “then” branch (no else), <xsl:choose> allows you to test multiple conditions in sequence and execute exactly one of the matching branches.
It is the way to write:
- If condition A → do this
- Else if condition B → do that
- Else if condition C → do something else
- Else (none of the above) → do default thing
Everyday analogy
Imagine you are deciding what to wear based on the weather:
|
0 1 2 3 4 5 6 7 8 9 |
If temperature < 10°C → wear thick jacket + scarf Else if temperature < 20°C → wear light jacket Else if temperature < 30°C → wear t-shirt Else → wear shorts + t-shirt |
That logic is exactly what <xsl:choose> is for.
2. Basic syntax – the pattern you will see 95% of the time
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<xsl:choose> <xsl:when test="condition-1"> <!-- output only if condition-1 is true --> <span style="color:red">Out of stock!</span> </xsl:when> <xsl:when test="condition-2"> <!-- output only if condition-1 was false AND condition-2 is true --> <span style="color:orange">Low stock</span> </xsl:when> <!-- you can have as many <xsl:when> as you want --> <xsl:otherwise> <!-- output only if NONE of the previous <xsl:when> were true --> <span style="color:green">In stock</span> </xsl:otherwise> </xsl:choose> |
Very important rules (memorize these):
- The processor evaluates the <xsl:when> branches in order — top to bottom
- As soon as one <xsl:when> test is true, it executes that branch and skips all the rest (including <xsl:otherwise>)
- <xsl:otherwise> is optional — if you leave it out and none of the <xsl:when> match, nothing is output
- You can have only one <xsl:otherwise> and it must be the last child
3. Realistic example 1 – Stock status with colors
Input XML fragment
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<product> <name>Wireless Mouse</name> <stock>45</stock> </product> <product> <name>USB-C Hub</name> <stock>8</stock> </product> <product> <name>Old Keyboard</name> <stock>0</stock> </product> |
XSLT code
|
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 |
<xsl:for-each select="product"> <div class="product"> <h3><xsl:value-of select="name"/></h3> <p>Stock: <xsl:value-of select="stock"/></p> <xsl:choose> <xsl:when test="stock = 0"> <div style="background:#fee2e2; color:#991b1b; padding:8px; border-radius:4px;"> Out of stock – pre-order available </div> </xsl:when> <xsl:when test="stock &lt; 10"> <div style="background:#fef3c7; color:#92400e; padding:8px; border-radius:4px;"> Low stock – only <xsl:value-of select="stock"/> left! </div> </xsl:when> <xsl:otherwise> <div style="background:#ecfdf5; color:#065f46; padding:8px; border-radius:4px;"> In stock – ready to ship </div> </xsl:otherwise> </xsl:choose> </div> </xsl:for-each> |
Result HTML (for the three products)
- Wireless Mouse → green “In stock” box
- USB-C Hub → orange “Low stock” box
- Old Keyboard → red “Out of stock” box
4. Example 2 – Price category badges
|
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 |
<xsl:for-each select="product"> <div class="product"> <h3><xsl:value-of select="name"/></h3> <p>₹<xsl:value-of select="price"/></p> <xsl:choose> <xsl:when test="number(price) >= 3000"> <span style="background:#d1fae5; color:#065f46; padding:4px 12px; border-radius:9999px;"> Premium </span> </xsl:when> <xsl:when test="number(price) >= 1000"> <span style="background:#dbeafe; color:#1d4ed8; padding:4px 12px; border-radius:9999px;"> Mid-range </span> </xsl:when> <xsl:otherwise> <span style="background:#f3f4f6; color:#4b5563; padding:4px 12px; border-radius:9999px;"> Budget </span> </xsl:otherwise> </xsl:choose> </div> </xsl:for-each> |
Result
- Items > ₹3000 → green “Premium” badge
- Items ₹1000–2999 → blue “Mid-range” badge
- Items < ₹1000 → gray “Budget” badge
5. Example 3 – Combining <xsl:choose> with attribute checks
|
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 |
<xsl:for-each select="product"> <div class="product"> <h3><xsl:value-of select="name"/></h3> <xsl:choose> <xsl:when test="@category = 'electronics'"> <span style="background:#e0f2fe; color:#1d4ed8; padding:2px 8px; border-radius:4px;"> Electronics </span> </xsl:when> <xsl:when test="@category = 'accessories'"> <span style="background:#fef3c7; color:#92400e; padding:2px 8px; border-radius:4px;"> Accessories </span> </xsl:when> <xsl:otherwise> <span style="background:#f3f4f6; color:#4b5563; padding:2px 8px; border-radius:4px;"> Other </span> </xsl:otherwise> </xsl:choose> <p>Price: ₹<xsl:value-of select="price"/></p> </div> </xsl:for-each> |
Lesson 6 – Common beginner mistakes & how to avoid them
Mistake 1 Putting <xsl:otherwise> in the middle or multiple times
|
0 1 2 3 4 5 6 7 8 9 10 |
<xsl:choose> <xsl:when>...</xsl:when> <xsl:otherwise>...</xsl:otherwise> <!-- correct – must be last --> <xsl:when>...</xsl:when> <!-- wrong – after otherwise --> </xsl:choose> |
Fix <xsl:otherwise> must be the last child and can appear only once
Mistake 2 Using <xsl:if> when you actually need else behavior
|
0 1 2 3 4 5 6 7 8 9 10 11 |
<xsl:if test="stock = 0"> Out of stock </xsl:if> <xsl:if test="stock > 0"> In stock </xsl:if> |
→ Wrong: both can be output if stock = 0 (because second condition is also true!)
Fix Use <xsl:choose> instead
Mistake 3 Forgetting number() when comparing numeric values
|
0 1 2 3 4 5 6 |
<xsl:when test="price < 500"> <!-- wrong – string comparison: "1499" < "500" is false! --> |
Fix
|
0 1 2 3 4 5 6 |
<xsl:when test="number(price) < 500"> |
Mistake 4 Writing complex logic inside test without parentheses
|
0 1 2 3 4 5 6 |
<xsl:when test="stock < 10 and price > 1000"> <!-- wrong – ambiguous precedence --> |
Fix
|
0 1 2 3 4 5 6 |
<xsl:when test="stock &lt; 10 and number(price) > 1000"> |
Lesson 7 – Try yourself exercises (do these!)
- Show “Free shipping” in green only if price > 2000
- Show “Low stock!” in orange if stock between 1 and 20
- Show “Out of stock” in red box if stock = 0
- Show “New arrival” badge if year > 2020 (add <year> to products)
- Show “Special offer” if price < 500 and stock > 30
- Show different category badges for electronics, accessories, and others
Summary – <xsl:if> & <xsl:choose> Quick Reference
| Goal | Best element / pattern | Important note / trap |
|---|---|---|
| Simple single condition | <xsl:if test=”…”> … </xsl:if> | No else branch — use <xsl:choose> if you need else |
| Multiple conditions / else behavior | <xsl:choose> + <xsl:when> + <xsl:otherwise> | <xsl:otherwise> must be last and can appear only once |
| Numeric comparison | number(price) < 500 | Without number(), string comparison is used |
| Check if element/attribute exists | title or count(title) > 0 | title is true if at least one exists |
| Check if element/attribute missing | not(title) or count(title) = 0 | Very common pattern |
| Combine conditions | stock < 10 and number(price) > 1000 | Use parentheses when mixing and/or |
Would you like to continue with one of these next?
- <xsl:choose> vs <xsl:if> – detailed comparison with examples
- Complex nested conditions – combining and/or/not with parentheses
- Checking existence of elements / attributes safely
- Real-world patterns — stock status, shipping messages, category badges, VIP indicators
- Debugging when <xsl:choose> / <xsl:if> does not trigger or shows wrong branch
- Using conditional logic inside <xsl:for-each> vs inside match templates
Just tell me which direction feels most useful or interesting for you right now! 😊
