Showing posts with label XSL. Show all posts
Showing posts with label XSL. Show all posts

Tuesday, August 26, 2008

XSLT - Keys implementation

XSLT Keys - xsl:key is used to declare keys. If I were to define xsl:key in my lanuage, I would say, key represents a collection of nodes (as specified in use attribute) which is filterd by specific pattern as defined by "match" attribute.

Syntax

<xsl:key name="name" match="pattern" use="expression"/>
Attributes

AttributeValue Description
name name Required. Specifies the name of the key
match pattern Required. Defines the nodes to which the key will be applied
use expression Required. The value of the key for each of the nodes

To explain keys better, let me take help of following example.

Below is a XML structure depicting information about various movies being played at "My Theater" on specific dates along with their show timings.

[code]
<?xml version="1.0" encoding="UTF-8"?>
<showtimes>
<id>my theater</id>
<film>
<name>The Big Show</name>
<show>
<date>06012006</date>
<time>0500</time>
</show>
<show>
<date>06012006</date>
<time>0700</time>
</show>
<show>
<date>06012006</date>
<time>0600</time>
</show>
<show>
<date>03012006</date>
<time>0700</time>
</show>
<show>
<date>08012006</date>
<time>0500</time>
</show>
<show>
<date>08012006</date>
<time>0700</time>
</show>
</film>
<film>
<name>The Truman Show</name>
<show>
<date>09012006</date>
<time>0600</time>
</show>
<show>
<date>09012006</date>
<time>0700</time>
</show>
<show>
<date>09012006</date>
<time>0700</time>
</show>
<show>
<date>08012006</date>
<time>0700</time>
</show>
<show>
<date>03012006</date>
<time>0600</time>
</show>
<show>
<date>03012006</date>
<time>0700</time>
</show>
</film>
</showtimes>
[/code]

Now, if one is to generate output as shown below, it is required that we group shows based on date. Now, to achieve this we would require xsl:key.

[output]

Movie Listings


Name of show : The Big Show
DATE = 03012006 | Show Timings : 0600 0700 0700
DATE = 06012006 | Show Timings : 0500 0600 0700
DATE = 08012006 | Show Timings : 0500 0700 0700

Name of show : The Truman Show
DATE = 09012006 | Show Timings : 0600 0700 0700
[/output]

Analyse the XSLT code to understand the functioning of keys.

[code]
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<--====grouping shows based on date under key with name shows======-->
<xsl:key name="shows" match="show" use="date"/>

<xsl:template match="/">
<html>
<head>
<title>Movie Listings</title>
</head>
<body>
<h1>Movie Listings</h1>
<hr/>
<--====looping for multiple films======-->
<xsl:for-each select="./showtimes/film">
<xsl:if test="position() > 1 ">
<hr/>
</xsl:if>
<xsl:apply-templates select="."/>
</xsl:for-each>
</body>
</html>
</xsl:template>

<xsl:template match="id"/>

<xsl:template match="film">
<div align="center">
<b><xsl:text>Name of show : </xsl:text></b>
<b><xsl:value-of select="self::film/child::name"/></b> <br/>
</div>
<--====fetching show node [who is same as of show node of position 1
when date is union/same]
======-->
<xsl:for-each select="show[count(key('shows', date)[1] | .) = 1]">
<xsl:sort select="substring(date, 5, 4)"/>
<xsl:sort select="substring(date, 1, 2)"/>
<xsl:sort select="substring(date, 3, 2)"/>
<div>
DATE = <xsl:value-of select="date"/><xsl:text> | </xsl:text>
<xsl:text>Show Timings : </xsl:text>
<--====iterating shows from key having specific date======-->
<xsl:for-each select="key('shows', date)">
<xsl:sort select="time"/>
<xsl:value-of select="time"/>
<xsl:if test="position() < last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
[/code]

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