The Push Model with XSLT
So how do we achieve the same sort of effect with XSLT? It
is not difficult to create an identical display to that above by using XSLT to
transform the XML into a document that combines HTML and CSS. We will be seeing
that later in the book, but for now we will create a simple HTML page.
We can do this easily since both HTML, as an application of
SGML, and XML, as a subset of SGML, use similar formats. The important thing is
that our XSLT stylesheet is well-formed XML. My file, Hamlet.xsl,
is one such example:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template
match="*|/"><xsl:apply-templates/></xsl:template>
<xsl:template match="EXTRACT">
<HTML>
<HEAD>
<TITLE>Hamlet</TITLE>
</HEAD>
<BODY>
<xsl:apply-templates/>
</BODY>
</HTML>
</xsl:template>
<xsl:template
match="ACT/TITLE">
<H1><xsl:value-of select="."/></H1>
</xsl:template>
<xsl:template
match="SCENE/TITLE">
<H2><xsl:value-of select="."/></H2>
</xsl:template>
<xsl:template
match="STAGEDIR">
<P><I><xsl:value-of
select="."/></I></P>
</xsl:template>
<xsl:template
match="SPEAKER">
<DIV><xsl:value-of select="."/></DIV>
</xsl:template>
<xsl:template match="LINE">
<DIV><xsl:value-of select="."/></DIV>
</xsl:template>
</xsl:stylesheet>
If we change the top of our
XML document HamletExtract.xml to
use the above transformation like this:
<?xml version="1.0"?>
<?xml-stylesheet
type="text/xsl" href="Hamlet.xsl"?>
<EXTRACT>
<ACT><TITLE>ACT I</TITLE>
and save it as HamletXsl.xml,
we can view the result
in IE5.
Note that to view this
directly, you will need to have MSXML3 installed in
replace mode (see Appendix E). Otherwise, you can just carry out the
transformation using XT or Saxon, and view the resulting HTML.
This is the result in IE5 (this time, you cannot use
Netscape since the processing instruction we have used is specific to IE):
and this is the HTML that is generated by XT that is,
using the command:
xt HamletExtract.xml Hamlet.xsl Hamlet.html
<HTML>
<HEAD>
<TITLE>Hamlet</TITLE>
</HEAD>
<BODY>
<H1>ACT I</H1>
<H2>SCENE I. Elsinore. A platform before
the castle.</H2>
<P>
<I>FRANCISCO at his post. Enter to him
BERNARDO</I>
</P>
<DIV>BERNARDO</DIV>
<DIV>Who's there?</DIV>
<DIV>FRANCISCO</DIV>
<DIV>Nay, answer me: stand, and unfold
yourself.</DIV>
<DIV>BERNARDO</DIV>
<DIV>Long live the king!</DIV>
<DIV>FRANCISCO</DIV>
<DIV>Bernardo?</DIV>
<DIV>BERNARDO</DIV>
<DIV>He.</DIV>
<DIV>FRANCISCO</DIV>
<DIV>You come most carefully upon your
hour.</DIV>
<DIV>BERNARDO</DIV>
<DIV>'Tis now struck twelve; get thee
to bed, Francisco.</DIV>
<DIV>FRANCISCO</DIV>
<DIV>For this relief much thanks: 'tis
bitter cold,</DIV>
<DIV>And I am sick at
heart.</DIV>
<DIV>BERNARDO</DIV>
<DIV>Have you had quiet
guard?</DIV>
<DIV>FRANCISCO</DIV>
<DIV>Not a mouse stirring.</DIV>
<DIV>BERNARDO</DIV>
<DIV>Well, good night.</DIV>
<DIV>If you do meet Horatio and
Marcellus,</DIV>
<DIV>The rivals of my watch, bid them
make haste.</DIV>
<DIV>FRANCISCO</DIV>
<DIV>I think I hear them. Stand, ho!
Who's there?</DIV>
</BODY>
</HTML>
I have used <DIV>
elements rather than,
say, <P>
elements, as they do not add vertical space. However, it is easy to change this
in the XSLT stylesheet if you prefer a different appearance. In later chapters,
we will use CSS to provide more control over the display format.
So how did this work? Let's work through again from the root
node. As before, the template for the root node causes all templates for its
children to be executed. In this case, we will execute the template for the <EXTRACT>
element next. This simply builds the structure of our HTML page, then executes
any templates matching its children such that results are inserted inside an
HTML <BODY>
element.
Most of the other templates are self-explanatory and build
up the HTML page. But what happens when we look for a template that matches the
<SPEECH>
element? In fact, we have no template for this element, but we do have a
template with match="*|/".
In XPath, the pipestem symbol (|)
acts as an "or" and the
asterisk means match any element. We will therefore execute
this template for the SPEECH element. Our template reaches the children of
this element (<SPEAKER>
and <LINE>)
because of the <xsl:apply-templates/>
in the template. How do we know not to apply this template for other elements,
such as <LINE>,
which have their own templates? This is a matter for which templates have
priority or precedence, topics we will cover later in the chapter.
As with the CSS example, this is clearly a push model of a
stylesheet. As we come across an element in the source document, we execute its
template. This type of stylesheet is typified by the presence of several short
templates and the use of <xsl:apply-templates/>.
Now we will
look at a stylesheet that uses the pull model something that is next to
impossible with CSS.