Friday, August 22, 2008

XSLT - Modes In Templates

"Modes allow an element to be processed multiple times, each time producing a different result." - [As defined by W3C]
Another way of interpreting modes can be, a mechanism which allows us to process same XML data island(by this I mean XML Node Set) in multiple ways.

To understand modes let us look at example below:

xml fragment
[code]

<?xml version="1.0" encoding="UTF-8"?>
<source>
<AAA id="a1" pos="start">
<BBB id="b1" />
<BBB id="b2" />
</AAA>
<AAA id="a2">
<BBB id="b3" />
<BBB id="b4" />
<CCC id="c1">
<CCC id="c2" />
</CCC>
<BBB id="b5">
<CCC id="c3" />
</BBB>
</AAA>
</source>

[/code]

XSLT snippet here will render XML element "ccc" in different color. Root template guides how child nodes will be processed. Refer the green comments in XSLT code.

[code]
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">
<xsl:apply-templates mode="red" />
<xsl:apply-templates mode="blue" />
<xsl:apply-templates />
</xsl:template>

<!--====== override default template to mode specifics ====== -->
<xsl:template match="*" mode="red">
<xsl:apply-templates mode="red"/>
</xsl:template>

<!--====== ccc template to mode specifics ====== -->
<xsl:template match="CCC" mode="red">
<div style="color:red">
parent:<xsl:value-of select="name(parent::*)"/><br/>
<xsl:value-of select="name()" />
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id" />
</div>
<xsl:apply-templates mode="red"/>
</xsl:template>

<!--====== override default template to mode specifics ====== -->
<xsl:template match="*" mode="blue">
<xsl:apply-templates mode="blue"/>
</xsl:template>

<!--====== ccc template to mode specifics ====== -->
<xsl:template match="CCC" mode="blue">
<div style="color:blue">
parent:<xsl:value-of select="name(parent::*)"/><br/>
<xsl:value-of select="name()" />
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id" />
</div>
<xsl:apply-templates mode="blue"/>
</xsl:template>

<xsl:template match="CCC">
<div style="color:purple">
parent:<xsl:value-of select="name(parent::*)"/><br/>
<xsl:value-of select="name()" />
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id" />
</div>
<!-- forcing child ccc element node to be processed as per "red" mode -->
<xsl:apply-templates mode="red"/>
</xsl:template>
</xsl:stylesheet>
[/code]


[output]
parent:AAA
CCC id=c1
parent:CCC
CCC id=c2
parent:BBB
CCC id=c3

parent:AAA
CCC id=c1
parent:CCC
CCC id=c2
parent:BBB
CCC id=c3

parent:AAA
CCC id=c1
parent:CCC
CCC id=c2
parent:BBB
CCC id=c3
[/output]

As one can see, modes help us in multiple processing of same nodes. Looking at the output one may wonder, I can achieve the same using xsl:if why do I need to use mode?
Well, in this condition there is no XML tree which needs to be processed differently, instead what we have here is single XML element "ccc", therefore xsl:if would suffice. However, consider a scenario, where we need to override default template and process a complicated XML tree, in multiple result cases, that is when we would see the relevance of modes.

Cheers

No comments: