On 16 November 1999, W3C announced that both XSL Transformations (XSLT) and XML Path Language (XPath) had become W3C Recommendations. XPath defines a simple way of referring to parts of an XML document. XSLT uses XPath in defining complex transformations applied to XML documents to create other XML documents. The reason for separating out the XPath part is that it is equally useful for defining the destination of a link so it will be an intrinsic part of the XPointer Recommendation as well.
Still to come is the final part of XSL, XSL-FO that will take the transformed XML tree and format it ready for output to a range of devices.
Suppose your CD collection was defined in XML with each CD marked up something like this:
<cdlist> <cd> <artist>Aatabou, Najat</artist> <title>The Voice of the Atlas</title> <label></label> <catalog>CDORBD 069</catalog> <time>61.15</time> <filed>C05 World</filed> <playlist> <work>Baghi narajah</work> <work>Finetriki</work> <work>Shouffi rhirou</work> <work>Lila ya s'haba</work> <work>Ouardatte lajnane</work> <work>Ditih</work> </playlist> </cd> <cd> <artist>Abshire, Nathan</artist> <title>French Blues</title> <label>Arhoolie</label> <catalog>CD 373</catalog> <time>78.0</time> <filed>C07 Cajun</filed> <playlist> <work>Pine grove blues</work> <work>Kaplan waltz</work> <work>French blues</work> <work>New Orleans waltz</work> <work>Pine grove boogie</work> <work>Hathaway waltz</work> </playlist> </cd> </cdlist>
If you had a few hundred CDs this gets to be a pretty large file and you may want shorter versions for specific purposes. One example of transforming the XML file into HTML (making sure it is a legal XML document by including all the end tags!) might be:
<xsl:for-each select="cdlist/cd"> <H1><xsl:value-of select="artist"/></H1> <p class="01"><xsl:value-of select="title"/></p> <p class="02">Label:<xsl:value-of select="label"/> Number:<xsl:value-of select="catalog"/> Time:<xsl:value-of select="time"/></p> <p class="03">Stored at:<xsl:value-of select="filed"/></p> <p class="04>Playlist</p> <ul> <xsl:for-each select="playlist/work"> <li class="05"><xsl:value-of /></li> </xsl:for-each> </ul> </xsl:for-each> </DIV>
Here we have the initial XSLT for-each element which selects part of the document to deal with based on the XPath cdlist/cd as an attribute value. Effectively this says let us go through each CD in turn.
Next we have a set of XSLT value-of elements that take the contents from a number of the text fields (title, label etc) and composes an HTML (really XML) document as an output tree. Walking over the tree produces the HTML document. The paragraph statements in HTML have class attributes associated with them so we can style them differently. Defining a suitable style sheet would produce something like this:
<style> type="text/css"> h1.01 { font-weight:bold; color:red; font-size:16pt; text-align:left} p.O1 { font-weight:bold; color: orange;font-size: 14pt} p.O2 { color:brown} p.O3 { font-weight:bold; color:orange; font-size: 14pt} p.O4 { color:brown} li.O5 {color:lime;font-weight:bold} </style> <h1 class="01">Aatabou, Najat</h1> <p class="O1">The Voice of the Atlas</p> <p class="O2">Label: , Number: CDORBD 069 , Time: 61.15</p> <p class="O3">Stored at: C05 World</p> <p class="O4">Playlist</P> <ul> <li class="O5">Baghi narajah</li> <li class="O5">Finetriki</li> <li class="O5">Shouffi rhirou</li> <li class="O5">Lila ya s'haba</li> <li class="O5">Ouardatte lajnane</li> <li class="O5">Ditih</li> </ul> <h1 class="01">Abshire, Nathan</h1> <p class="O1">French Blues</p> <p class="O2">Label: Arhoolie , Number: CD 373 , Time: 78.0</p> <p class="O3">Stored at: C07 Cajun</p> <p class="O4">Playlist</p> <ul> <li class="O5">Pine grove blues</li> <li class="O5">Kaplan waltz</li> <li class="O5">French blues</li> <li class="O5">New Orleans waltz</li> <li class="O5">Pine grove boogie</li> <li class="O5">Hathaway waltz</li> </ul>
The following gives a flavour of the XSLT elements available:
XSL Element | Description |
---|---|
apply-templates | Find correct template to apply |
attribute | Generates attribute node and applies to element |
cdata | Outputs a CDATA section in the output |
choose | Conditional testing with otherwise and when |
copy | Copy target node from source to output |
element | Generates an element in the output with specified name |
for-each | Applies same template to multiple document nodes |
if | Conditional test |
node-name | Inserts current node name into output |
template | Defines a template for output based on a pattern |
value-of | Evaluates select and outputs value |
Let us consider all the CDs with artists whose surname starts with the letter A and how we might produce a shortened table with just the artist, the title and where to find it:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <div> <table style="font-weight:bold" border="1"> <thead> <tr style="color:lime"> <th>Artist</th><th>Title</th><th>Stored At</th> </tr> </thead> <tbody> <xsl:for-each select="cdlist/cd"> <tr> <td style="color:yellow"> <xsl:value-of select="artist"/></td> <td style="color: orange"><xsl:value-of select="title"/></td><td style="color:red"><xsl:value-of select="filed"/></td> </tr> </xsl:for-each> </tbody> </table> </div> </xsl:template> </xsl:stylesheet>
This would produce something like this:
Artist | Title | Stored At |
---|---|---|
Aatabou, Najat | The Voice of the Atlas | C05 World |
Abshire, Nathan | French Blues | C07 Cajun |
Acuff, Roy | The Essential Roy Acuff 1936-1949 | C06 Country |
Aglukark, Susan | This Child | C05 World |
Akhtar, Najma | Qareeb | C05 World |
Aldina | Aldina | C08 Fado |
Allen, Deborah | Delta Dreamland | C06 Country |
Allen, Deborah | All That I Am | C06 Country |
Allen, Geri | Segments | C13 Jazz Modern |
Allen, Red | I Was Born To Swing | C04 Jazz Series |
One nice touch is that changing the XSL element to:
<xsl:for-each select="cdlist/cd" order-by="title">
would give us instead:
Artist | Title | Stored At |
---|---|---|
Aldina | Aldina | C08 Fado |
Allen, Deborah | All That I Am | C06 Country |
Allen, Deborah | Delta Dreamland | C06 Country |
Abshire, Nathan | French Blues | C07 Cajun |
Allen, Red | I Was Born To Swing | C04 Jazz Series |
Akhtar, Najma | Qareeb | C05 World |
Allen, Geri | Segments | C13 Jazz Modern |
Acuff, Roy | The Essential Roy Acuff 1936-1949 | C06 Country |
Aatabou, Najat | The Voice of the Atlas | C05 World |
Aglukark, Susan | This Child | C05 World |
We could emphasise the different styles of music by something like:
<tbody> <xsl:for-each select="cdlist/cd"> <tr> <xsl:attribute name="STYLE">color: <xsl:choose> <xsl:when test="filed[. $eq$ 'C05 World']">blue</xsl:when> <xsl:when test="filed[. $eq$ 'C06 Country']">yellow</xsl:when> <xsl:when test="filed[. $eq$ 'C08 Fado']">gray</xsl:when> <xsl:otherwise>red</xsl:otherwise> </xsl:choose> </xsl:attribute> <td><xsl:value-of select="artist"/></td> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="filed"/></td> </tr> </xsl:for-each> </tbody>
which would give us:
Artist | Title | Stored At |
---|---|---|
Aatabou, Najat | The Voice of the Atlas | C05 World |
Abshire, Nathan | French Blues | C07 Cajun |
Acuff, Roy | The Essential Roy Acuff 1936-1949 | style="color:yellow">C06 Country |
Aglukark, Susan | This Child | C05 World |
Akhtar, Najma | Qareeb | C05 World |
Aldina | Aldina | C08 Fado |
Allen, Deborah | Delta Dreamland | C06 Country |
Allen, Deborah | All That I Am | C06 Country |
Allen, Geri | Segments | C13 Jazz Modern |
Allen, Red | I Was Born To Swing | C04 Jazz Series |
So far we have done reasonably simple selections using XPath. A more refined selection might be:
<xsl:for-each select="cdlist/cd[filed='C06 Country']" >
which would produce:
Artist | Title | Stored At |
---|---|---|
Acuff, Roy | The Essential Roy Acuff 1936-1949 | C06 Country |
Allen, Deborah | Delta Dreamland | C06 Country |
Allen, Deborah | All That I Am | C06 Country |
XPath allows the user to walk over the XML tree in many different directions or axes. So far we have been doing our walking down from the current or context node in the direction of the descendants of that node. Thus we started at the root node (defined by '/') and went from cdlist to cd and then down further to the individual records. XPath splits the complete tree up into a set of separate 'axes'. The major ones are:
The indented axes are subsets of the outer axes. So for the nodes in the XML tree, five axes (ancestor, descendant, preceding, following and self) define all the nodes in the tree. This is illustrated as follows :
A location path then consists of a set of location steps each of the form:
For example:
<span style="color:brown" >child::</span><span style="color:blue">para</span><span style="color:red">[position()=1]</span>
This selects the first para child node of the context node. If omitted, the axis is assumed to be the child axis. There are some special node tests defined that come in useful.
Here is a flavour of some of the paths that could be defined using XPath:
/descendent::para
Selects all the para elements in the document
/doc/chapter[3]/section[2]
Selects the second section node of the third chapter node of the doc node of the document
*/para
Selects all para grandchildren of the context node
XSLT and XPath are essential components in the move from HTML to XML and with good support in IE5 we should be seeing applications appearing almost immediately.