Control Flow Elements
The following five elements allow us to control execution
within a template in a manner analogous to procedural languages. These are <xsl:if>,
<xsl:choose>,
<xsl:when>,
<xsl:otherwise>,
and <xsl:for-each>.
The first of these gives a simple if... then...
construct. The next three provide the equivalent of if...
then...
else...
and the switch
statement in many languages, and the last provides looping.
<xsl:if>
This element is used within a template purely to make
execution of the enclosed statements conditional on the result of a test. It
has a mandatory test attribute, which contains an expression that will
return a Boolean result. The enclosed statements will be executed if the result
of the test is true.
The test expression may involve the use of XSLT functions.
We shall cover a couple of the functions included in XSLT at the end of this
chapter, but their use in the following code is self-explanatory.
Common uses for <xsl:if>
are testing for error
conditions, or treating the first or last elements of a collection differently
from the others. For example, the following template (ListCharacters.xsl)
lists all the characters in Hamlet, placing a comma and space after all but the
last:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"
indent="yes"/>
<xsl:template match="PLAY">
<HTML
xmlns="http://www.w3.org/TR/REC-html40">
<HEAD>
<TITLE>Listing Characters</TITLE>
</HEAD>
<BODY>
<P>
The characters in Hamlet are:
<xsl:for-each select="//PERSONA">
<xsl:value-of select="."/>
<xsl:if test = "position() != last()">, </xsl:if>
</xsl:for-each>
</P>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
And this is the result after being applied to Hamlet.xml:
Note that this element only allows an if...
then...;
if we want an else...,
we must use <xsl:choose>,
which we will look at next.
<xsl:choose>, <xsl:when>, and
<xsl:otherwise>
These elements provide the equivalent of a switch
statement, and can therefore also be used to provide an if...
then...
else...
construct.
Here is an example of them in use in HamletWithLines.xsl,
which is modified from a previous stylesheet (Hamlet.xsl):
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
method="html" indent="yes"/>
<xsl:template
match="*|/"><xsl:apply-templates/></xsl:template>
<xsl:template
match="text()|@*"><xsl:value-of
select="."/></xsl:template>
<xsl:template
match="EXTRACT">
<HTML
xmlns="http://www.w3.org/TR/REC-html40">
<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[position()=last()]">
<DIV>
<xsl:value-of
select="."/>
<xsl:choose>
<xsl:when
test="../SPEAKER='BERNARDO'">
<HR
style="color:silver"/>
</xsl:when>
<xsl:when
test="../SPEAKER='FRANCISCO'">
<HR
style="color:black"/>
</xsl:when>
<xsl:otherwise>
<!-- this is
the trap for unrecognized speakers -->
<DIV
style="color:silver">
!! oops, I don't
know this speaker !!
</DIV>
</xsl:otherwise>
</xsl:choose>
</DIV>
</xsl:template>
<xsl:template
match="LINE"><xsl:value-of
select="."/></xsl:template>
</xsl:stylesheet>
I have added the <xsl:output>
element and HTML
namespace that we did not know about earlier. But the important part is the new
template, which simply puts a different shade of horizontal rule under the last
line of each speech, depending on the speaker. This is how it looks when
applied to HamletExtract.xml:
In my first attempt at this stylesheet, I misspelled the
name "FRANCISCO" as "FRANSISCO" in the new template. This
was the result:
As you can see, the <xsl:otherwise>
can be used to
trap errors, as it has done here.