I am a beginner to the XSLT and I am a bit confused on how to use xsl:when
. Please find my sample XSLT code below with expected output and the actual output I am getting from the XSLT. Could you please suggest your solution and explain what I am doing incorrect while using xsl:when
.
XML
<source>
<bold>Hello, world.</bold>
<italic>fine.</italic>
<red>I am </red>
</source>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="source">
<xsl:choose>
<xsl:when test="bold">
<xsl:element name="p">
<xsl:element name="b">
<xsl:value-of select="bold"></xsl:value-of>
</xsl:element>
</xsl:element>
</xsl:when>
<xsl:when test="red">
<xsl:element name="p">
<xsl:value-of select="red"></xsl:value-of>
</xsl:element>
</xsl:when>
<xsl:when test="italic">
<xsl:element name="p">
<xsl:element name="i">
<xsl:value-of select="italic"></xsl:value-of>
</xsl:element>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="p">
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
EXPECTED OUTPUT
<p><b>Hello, world.</b></p>
<p><i>fine.</i></p>
<p style="color:red;">I am </p>
ACTUAL OUTPUT
<p><b>Hello, world.</b></p>
If possible can you show how we can Implement this expected output in
xsl:choose?
To implement this using xsl:choose
you could do something like:
<xsl:template match="source">
<div>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="source/*">
<xsl:choose>
<xsl:when test="self::bold">
<p><b><xsl:apply-templates/></b></p>
</xsl:when>
<xsl:when test="self::italic">
<p><i><xsl:apply-templates/></i></p>
</xsl:when>
<xsl:when test="self::red">
<p style="color:red;"><xsl:apply-templates/></p>
</xsl:when>
<xsl:otherwise>
<p><xsl:apply-templates/></p>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Note that here the template using xsl:choose
matches the actual elements children of source
- unlike your attempt that took place at the parent source
level.
This means that each element tests itself (hence the use of the self
axis) and itself only. Unlike your attempt, that tested the children of source
and returned true for the first test if any child of source
was <bold>
.
Keep in mind that just because it is possible, it doesn't mean it's the best way to do it.
Note: Figuring out what your input XML would have been to produce the shown output given your XSLT was an unnecessary challenge, really. Please include the input in your question next time.
Explanation: When your template matches the source
element, xsl:choose
finds only the first xsl:when
condition whose test passes. A better organization to achieve your desired output would break the xsl:when
elements out into their own xsl:templates
...
Given this input XML:
<source>
<bold>Hello, world.</bold>
<italic>fine.</italic>
<red>I am </red>
</source>
This XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="bold">
<p><b><xsl:apply-templates/></b></p>
</xsl:template>
<xsl:template match="red">
<p style="color:red;"><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="italic">
<p><i><xsl:apply-templates/></i></p>
</xsl:template>
</xsl:stylesheet>
Will produce the requested output:
<p><b>Hello, world.</b></p>
<p><i>fine.</i></p>
<p style="color:red;">I am </p>
But you really should add this additional template:
<xsl:template match="source">
<div><xsl:apply-templates/></div>
</xsl:template>
To produce this well-formed output XML:
<div>
<p><b>Hello, world.</b></p>
<p><i>fine.</i></p>
<p style="color:red;">I am </p>
</div>