This chapter is based on Chapter 6 of Erik Ray's book [Ray 2001], Chapter 12 of the Deitel, et.al. tome [Deitel 2001], Chapter 12 of Elliotte Rusty Harold's book [Harold 1999], plus additional material from the web.
There is a good tutorial available in the Guide to the XML Galaxy from Zvon.
So far, our XML documents, and their associated DTDs, have been static objects. We now see how XSL is used to transform these documents into other useful formats. To do this we need the original XML document, a stylesheet written in the XSLT language, and some suitable software (freely available on the web :-).
Here are some reasons for transforming an XML document into another form.
Obviously these tasks could be achieved by writing suitable programs in languages such as Perl and Visual Basic. XSLT is designed to perform these transformations (and nothing else) efficiently. It is also easy to learn and read.
The Extensible Stylesheet Language for Transformation (XSLT) is a subset of XSL. It's a specification of how to match elements and what XML to produce as output. XML documents are represented as tree-shaped diagrams with each part of the structure represented as a node in the tree. There are seven different types of node.
Figure 1 illustrates an XML document containing all these types of nodes.
<?xml version="1.0"?>
<!-- Mick's favourite -->
<sandwich xmlns="http://www.dcs.bbk.ac.uk/~mick/ns">
<ingredient type="Bovril">
Savoury spread
<?knife spread thickly?>
</ingredient>
<ingredient>
Bread
<!-- Brown wholemeal preferably -->
</ingredient>
</sandwich>
|
Figure 2 is the aboreal view of Mick's Sandwich. The root
node contains a comment and the document root element,
<sandwich>, which in turn contains a
namespace declaration and two child elements of type
<ingredient>.
The first <ingredient> contains an
attribute (type="Bovril"), a processing
instruction (Spread thickly), and some text
(Savoury spread). The second
<ingredient> contains some text
(Bread) and a comment.
XSLT relies on the principle that we can break down the transformation into smaller, more manageable chunks. Each transformation rule focuses on one level, without dealing with the rest of the tree. It contains references to other rules that carry out the processing all the way down to the leaves. Continuing with the sandwich example.
<HTML>,
<HEAD>, and
<BODY> elements. Process the branches.
<sandwich> element. Generate
a suitable heading.
<ingredient> element as a
bulleted list item containing the text node.
This is where the sandwich example runs out of steam!
Instead, consider the on-line calendar seen
earlier. The notion of containment is an important
benefit of XML markup. A rule matching a container element
(e.g. <date>) can be used to set up the
surrounding structure for the children
(e.g. <event>) to follow.
XSLT is designed to make it easy to work on the document
tree by defining template rules interspersed with
output. The processor knows the difference between them
because the XSLT elements are in the xsl
namespace. The special elements
<xsl:apply-templates> and
<xsl:value-of> navigate around the tree
and insert node values respectively. Figure 3 is the
complete stylesheet for generating the HTML version of the
on-line calendar. Note that, in general, each element of
the DTD has a corresponding template indicating what
transformations (e.g. markup) are to be performed.
<?xml version="1.0"?>
<!-- cal2html.xsl -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="calendar">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="year">
<H1>Calendar for <xsl:value-of select="@value"/></H1>
<UL>
<xsl:apply-templates/>
</UL>
</xsl:template>
<xsl:template match="date">
<LI>
<xsl:value-of select="@day"/>/<xsl:value-of select="@month"/>
<OL>
<xsl:apply-templates/>
</OL>
</LI>
</xsl:template>
<xsl:template match="event">
<LI value="{@time}">
<xsl:apply-templates/>
</LI>
</xsl:template>
</xsl:stylesheet>
|
The stylesheet has to be a well-formed XML document. The
root element is always <xsl:stylesheet>
and it contains a number of <xsl:template
match="..."> elements. These specify how to
process particular elements. By default, elements are
processed in sequence with leaf elements represented by
their text nodes. Individual attribute values are obtained
using the <xsl:value-of select="@..."/>
empty element. The construct {@...} is a
convenient way of including attribute values inside output
elements.
Returning to Figure 3. The stylesheet matches the root
element <calendar> which matches the
templates of its children; this is the default behaviour.
Any <year> element generates an HTML
<H1> heading and applies the templates of
its children as items in an unordered list. Each
<date> element outputs the values of the
day and month attributes and
applies the templates of its children as items in an ordered
list.
Finally, each <event> element uses the
value of its time attribute as its value in the
ordered list and, by default, its text is used as the
content of the list item.
There are a number of other XSLT constructs that provide better control over the way the document tree is processed. Figure 4 is a listing of the stylesheet used to transform our CD collection into HTML.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="cdcollection">
<xsl:apply-templates select="album"/>
</xsl:template>
<xsl:template match="album">
<H1>
<xsl:apply-templates select="title"/>
</H1>
<H2>
<xsl:apply-templates select="artist"/>
</H2>
<OL>
<xsl:for-each select="track">
<LI>
<xsl:value-of select="text()"/>
<xsl:if test="@time">
(<xsl:value-of select="@time"/>)
</xsl:if>
</LI>
</xsl:for-each>
</OL>
</xsl:template>
<xsl:template match="artist">
<xsl:value-of select="text()"/>
<xsl:if test="position()!=last()">, </xsl:if>
</xsl:template>
</xsl:stylesheet>
|
This figure has introduced the following new constucts (XSLT elements).
<xsl:if test="...">
<xsl:for-each select="...">
XSLT defines a set of default rules that makes it easier to write stylesheets. If no rule from the stylesheet matches, these default rules are invoked. These are the default rules for each type of node.
<xsl:template match="/"> <xsl:apply-templates/> </xsl:template>
<xsl:template match="*"> <xsl:apply-templates/> </xsl:template>
<xsl:template match="@*"> <xsl:value-of select="."/> </xsl:template>
<xsl:value-of> element in every template
to output text; this is done by default.
<xsl:template match="text()"> <xsl:value-of select="."/> </xsl:template>
<xsl:template match="comment()"/>
<xsl:template match="processing-instruction()"/>
The minimal stylesheet that matches any well-formed XML document is illustrated in Figure 5.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
|
Applying this bland stylesheet to our CD collection produces the predictable result illustrated in Figure 6.
Sheryl Crow
Sheryl Crow
A & M Records
maybe angels
a change
home
sweet rosalyn
if it makes you happy
redemption day
hard to make a stand
everyday is a winding road
love is a good thing
oh marie
superstar
the book
ordinary morning
free man
Slide on This
Ronnie Wood
KOCH International
Somebody Else Might
Testify
Ain't Rock'n Roll
Josephine
Knock Yer Teeth Out
Ragtime Annie (Lillie's Bordello)
Must Be Love
Fear For Your Future
Show Me
Always Wanted More
Thinkin'
Like It
Breath On Me
Somebody Else Might (Remix)
|
Note that whitespace has been preserved as text nodes which are output. The HTML output given earlier ignores this whitespace.
The following is a non-exhaustive list of the XSLT transformation functions in alphabetical order.
<xsl:apply-templates select="...">
<xsl:attribute name="...">
<xsl:attribute-set name="...">
<xsl:call-template select="...">
<xsl:choose>
<xsl:when> elements evaluated sequentially.
<xsl:comment>
<xsl:element name="...">
<xsl:for-each select="...">
<xsl:if test="...">
<xsl:number value="...">
<xsl:otherwise>
<xsl:choose> element.
<xsl:output method="..."/>
<xsl:param name="...">
<xsl:sort select="..."/>
<xsl:template match="...">
<xsl:template name="...">
<xsl:text>
<xsl:transform>
<xsl:stylesheet>
<xsl:value-of select="...">
<xsl:variable name="...">
<xsl:when test="...">
<xsl:choose>.
There are a number of additional elements providing advanced techniques; these are beyond the scope of this chapter. Consult Eric Ray's book [Ray 2001] for further details and examples.