Book HomeXSLTSearch this book

Appendix A. XSLT Reference

This chapter is a complete reference to all the elements defined in the XSLT specification.

<xsl:apply-imports> Allows you to apply any overridden templates to the current node. It is comparable to the super() method in Java.

Category

Instruction

Required Attributes

None.

Optional Attributes

None.

Content

None. <xsl:apply-imports> is an empty element.

Appears in

<xsl:apply-imports> appears inside a template.

Defined in

XSLT section 5.6, Overriding Template Rules.

Example

Here is a short XML file we'll use to illustrate <xsl:apply-imports>:

<?xml version="1.0"?>
<test>

  <p>This is a test XML document used by several 
  of our sample stylesheets.</p>
  <question>
    <text>When completed, the Eiffel Tower was the 
    tallest building in the world.</text>
    <true correct="yes">You're correct!  The Eiffel 
    Tower was the world's tallest building until 1930.</true>
    <false>No, the Eiffel Tower was the world's tallest 
    building for over 30 years.</false>
  </question>
  <question>
    <text>New York's Empire State Building knocked the 
    Eiffel Tower from its pedestal.</text>
    <true>No, that's not correct.</true>
    <false correct="yes">Correct!  New York's Chrysler 
    Building, completed in 1930, became the world's tallest.</false>
  </question>
</test>

Here's the stylesheet we'll import:

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

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:for-each select="//text|//true|//false">
          <p>
            <xsl:apply-templates select="."/>
          </p>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="text">
    <xsl:text>True or False: </xsl:text><xsl:value-of select="."/>
  </xsl:template>

  <xsl:template match="true|false">
    <b><xsl:value-of select="name()"/>:</b>
    <br/>
    <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>

This template provides basic formatting for the <true> and <false> elements, as shown in Figure A-1.

Figure A-1

Figure A-1. Document generated with basic formatting

We'll illustrate <xsl:apply-imports> with this stylesheet, which imports the other stylesheet:

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

  <xsl:import href="imported.xsl"/>
  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>A Brief Test</title>
        <style>
          <xsl:comment> 
            p.question {font-size: 125%; font-weight: bold} 
            p.right    {color: green}
            p.wrong    {color: red}
          </xsl:comment>
        </style>
      </head>
      <body>
        <h1>A Brief Test</h1>
        <xsl:for-each select="//question">
          <table border="1">
            <xsl:apply-templates select="text"/>
            <xsl:apply-templates select="true|false"/>
          </table>
          <br/>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="text">
    <tr bgcolor="lightslategray">
      <td>
        <p class="question">
          <xsl:apply-imports/>
        </p>
      </td>
    </tr>
  </xsl:template>

  <xsl:template match="true|false">
    <tr>
      <td>
        <xsl:choose>
          <xsl:when test="@correct='yes'">
            <p class="right">
              <xsl:apply-imports/>
            </p>
          </xsl:when>
          <xsl:otherwise>
            <p class="wrong">
              <xsl:apply-imports/>
            </p>
          </xsl:otherwise>
        </xsl:choose>
      </td>
    </tr>
  </xsl:template>

</xsl:stylesheet>

Using <xsl:apply-imports> allows us to augment the behavior of the imported templates. Our new stylesheet produces this document:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>A Brief Test</title>
<style>
<!-- 
            p.question {font-size: 125%; font-weight: bold} 
            p.right    {color: green}
            p.wrong    {color: red}
          -->
</style>
</head>
<body>
<h1>A Brief Test</h1>
<table border="1">
<tr bgcolor="lightslategray">
<td>
<p class="question">True or False: When completed, the Eiffel 
Tower was the tallest building in the world.</p>
</td>
</tr>
<tr>
<td>
<p class="right">
<b>true:</b>
<br>You're correct!  The Eiffel Tower was the world's tallest 
building until 1930.</p>
</td>
</tr>
<tr>
<td>
<p class="wrong">
<b>false:</b>
<br>No, the Eiffel Tower was the world's tallest building for 
over 30 years.</p>
</td>
</tr>
</table>
<br>
<table border="1">
<tr bgcolor="lightslategray">
<td>
<p class="question">True or False: New York's Empire State Building 
knocked the Eiffel Tower from its pedestal.</p>
</td>
</tr>
<tr>
<td>
<p class="wrong">
<b>true:</b>
<br>No, that's not correct.</p>
</td>
</tr>

<tr>
<td>
<p class="right">
<b>false:</b>
<br>Correct!  New York's Chrysler Building, completed in 1930, 
became the world's tallest.</p>
</td>
</tr>
</table>
<br>
</body>
</html>

When rendered, this stylesheet looks like Figure A-2.

Figure A-2

Figure A-2. Document generated with <xsl:apply-imports>

<xsl:apply-templates>Instructs the XSLT processor to apply the appropriate templates to a node-set.

Category

Instruction

Required Attributes

None.

Optional Attributes

select
Contains an XPath expression that selects the nodes to which templates should be applied. Valid values include * to select the entire node-set. Without this attribute, all element children of the current node are selected.

mode
Defines a processing mode, a convenient syntax that lets you write specific templates for specific purposes. For example, I could write an <xsl:template> with mode="toc" to process a node for the table of contents of a document, and other <xsl:template>s with mode="print", mode="online", mode="index", etc. to process the same information for different purposes.

Content

The <xsl:apply-templates> element can contain any number of <xsl:sort> and <xsl:with-param> elements. In most cases, <xsl:apply-templates> is empty.

Appears in

<xsl:apply-templates> appears inside a template.

Defined in

XSLT section 5.4, Applying Template Rules.

Example

In our case study (see Chapter 9, "Case Study: The Toot-O-Matic"), we needed to create several different outputs from the same data. We addressed this need with the mode attribute of the <xsl:apply-templates> element. Here's the main template (match="/"):

<xsl:template match="/">
  <xsl:apply-templates select="tutorial" mode="build-main-index"/>
  <redirect:write select="concat($curDir, $fileSep, 'index.html')"> 
    <xsl:apply-templates select="tutorial" mode="build-main-index"/>
  </redirect:write>
  <xsl:apply-templates select="tutorial" mode="build-section-indexes"/>
  <xsl:apply-templates select="tutorial" mode="build-individual-panels"/>
  <xsl:apply-templates select="tutorial" mode="generate-graphics"/>
  <xsl:apply-templates select="tutorial" mode="generate-pdf-file">
    <xsl:with-param name="page-size" select="'ltr'"/>
  </xsl:apply-templates>

  <xsl:apply-templates select="tutorial" mode="generate-pdf-file">
    <xsl:with-param name="page-size" select="'a4'"/>
  </xsl:apply-templates>
  <xsl:apply-templates select="tutorial" mode="generate-zip-file"/>
</xsl:template>

Notice that this example selects the <tutorial> element eight times, but applies templates with a different mode (or different parameters for the same mode) each time.

<xsl:attribute>Allows you to create an attribute in the output document. The advantage of <xsl:attribute> is that it allows you to build the attribute's value from parts of the input document, hardcoded text, values returned by functions, and any other value you can access from your stylesheet.

Category

Instruction

Required Attributes

name
The name attribute defines the name of the attribute created by the <xsl:attribute> element. (No matter how you try to say this, talking about the attributes of the <xsl:attribute> element is confusing, isn't it?)

Optional Attributes

namespace
The namespace attribute defines the namespace URI that should be used for this attribute in the output document. You don't have control over the namespace prefix used; the only thing you specify with the namespace attribute is the URI of the namespace.

Content

An XSLT template. In other words, you can build the contents of an attribute with <xsl:choose> elements, <xsl:text>, and <xsl:value-of> elements.

Appears in

<xsl:attribute> appears inside a template.

Defined in

XSLT section 7.1.3, Creating Attributes with xsl:attribute.

Example

For this example, we want to create an HTML table from the following XML document:

<?xml version="1.0"?>
<list xml:lang="en">
  <title>Albums I've bought recently:</title>
  <listitem>The Sacred Art of Dub</listitem>
  <listitem>Only the Poor Man Feel It</listitem>
  <listitem>Excitable Boy</listitem>
  <listitem xml:lang="sw">Aki Special</listitem>
  <listitem xml:lang="en-gb">Combat Rock</listitem>
  <listitem xml:lang="zu">Talking Timbuktu</listitem>
  <listitem xml:lang="jz">The Birth of the Cool</listitem>
</list>

We'll create a table that has each <listitem> in a separate row in the right column of the table, and a single cell with rowspan equal to the number of <listitem> elements in the XML document on the left. Clearly we can't hardcode a value for the rowspan attribute because the number of <listitem>s can change. This stylesheet uses <xsl:attribute> to do what we want:

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

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title><xsl:value-of select="list/title"/></title>
      </head>
      <body>
        <xsl:apply-templates select="list"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="list">
    <table border="1" width="75%">
      <tr>
        <td bgcolor="lightslategray" width="100" align="right">
          <xsl:attribute name="rowspan">
            <xsl:value-of select="count(listitem)"/>
          </xsl:attribute>
          <p style="font-size: 125%">
            <xsl:value-of select="title"/>
          </p>
        </td>
        <td>
          <xsl:value-of select="listitem[1]"/>
        </td>
      </tr>
      <xsl:for-each select="listitem">
        <xsl:if test="position() > 1">
          <tr>
            <td>
              <xsl:value-of select="."/>
            </td>
          </tr>
        </xsl:if>
      </xsl:for-each>
    </table>
  </xsl:template>

</xsl:stylesheet>

Here is the generated HTML document:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Albums I've bought recently:</title>
</head>
<body>
<table width="75%" border="1">
<tr>
<td align="right" width="100" rowspan="7" bgcolor="lightslategray">
<p style="font-size: 125%">Albums I've bought recently:</p>
</td><td>The Sacred Art of Dub</td>
</tr>
<tr>
<td>Only the Poor Man Feel It</td>
</tr>
<tr>
<td>Excitable Boy</td>
</tr>
<tr>
<td>Aki Special</td>
</tr>
<tr>
<td>Combat Rock</td>
</tr>
<tr>
<td>Talking Timbuktu</td>
</tr>
<tr>
<td>The Birth of the Cool</td>
</tr>
</table>
</body>
</html>

Notice that the <td> element had several attributes hardcoded on it; those attributes are combined with the attribute we created with <xsl:attribute>. You can have as many <xsl:attribute> elements as you want, but they must appear together as the first thing inside the element to which you add attributes. Figure A-3 shows how our generated HTML document looks.

Figure A-3

Figure A-3. Document with generated Attributes

Be aware that in this instance, we could have used an attribute-value template. You could generate the value of the rowspan attribute like this:

<td bgcolor="lightslategray" rowspan="{count(listitem)}"
  width="100" align="right">

The expression in curly braces ({}) is evaluated and replaced with whatever its value happens to be. In this case, count(listitem) returns the number 7, which becomes the value of the rowspan attribute.

<xsl:attribute-set>Allows you to define a group of attributes for the output document. You can then reference the entire attribute set with its name, rather than create all attributes individually.

Category

Top-level element

Required Attributes

name
Defines the name of this attribute set.

Optional Attributes

use-attribute-sets
Lists one or more attribute sets that should be used by this attribute set. If you specify more than one set, separate their names with whitespace characters. You can use this attribute to embed other <xsl:attribute-set>s in this one, but be aware that an <xsl:attribute-set> that directly or indirectly embeds itself results in an error. In other words, if attribute set A embeds attribute set B, which in turn embeds attribute set C, which in turn embeds attribute set A, the XSLT processor will signal an error.

Content

One or more <xsl:attribute> elements.

Appears in

<xsl:stylesheet>. <xsl:attribute-set> is a top-level element and can only appear as a child of <xsl:stylesheet>.

Defined in

XSLT section 7.1.4, Named Attribute Sets.

Example

For this example, we'll create a stylesheet that defines attribute sets for regular text, emphasized text, and large text. Just for variety's sake, we'll use the Extensible Stylesheet Language Formatting Objects (XSL-FO) specification to convert our XML document into a PDF file. Here's our stylesheet:

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

  <xsl:output method="html"/>

  <xsl:attribute-set name="regular-text">
    <xsl:attribute name="font-size">12pt</xsl:attribute>
    <xsl:attribute name="font-family">sans-serif</xsl:attribute>
  </xsl:attribute-set>

  <xsl:attribute-set name="emphasized-text" use-attribute-sets="regular-text">
    <xsl:attribute name="font-style">italic</xsl:attribute>
  </xsl:attribute-set>

  <xsl:attribute-set name="large-text" use-attribute-sets="regular-text">
    <xsl:attribute name="font-size">18pt</xsl:attribute>
    <xsl:attribute name="font-weight">bold</xsl:attribute>
    <xsl:attribute name="space-after.optimum">21pt</xsl:attribute>
  </xsl:attribute-set>

  <xsl:template match="/">
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
        <fo:simple-page-master margin-right="75pt" margin-left="75pt" 
          page-height="11in" page-width="8.5in"
          margin-bottom="25pt" margin-top="25pt" master-name="main">
          <fo:region-before extent="25pt"/>
          <fo:region-body margin-top="50pt" margin-bottom="50pt"/>
          <fo:region-after extent="25pt"/>
        </fo:simple-page-master>
        <fo:page-sequence-master master-name="standard">
          <fo:repeatable-page-master-alternatives>
            <fo:conditional-page-master-reference master-name="main" 
              odd-or-even="any"/>
          </fo:repeatable-page-master-alternatives>
        </fo:page-sequence-master>
      </fo:layout-master-set>
      
      <fo:page-sequence master-name="standard">
        <fo:flow flow-name="xsl-region-body">
          <xsl:apply-templates select="list"/>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>

  <xsl:template match="list">
    <fo:block xsl:use-attribute-sets="large-text">
      <xsl:value-of select="title"/>
    </fo:block>
    <fo:list-block provisional-distance-between-starts="0.4cm"
      provisional-label-separation="0.15cm">
      <xsl:for-each select="listitem">
        <fo:list-item start-indent="0.5cm" space-after.optimum="17pt">
          <fo:list-item-label>
            <fo:block xsl:use-attribute-sets="regular-text">*</fo:block>
          </fo:list-item-label>
          <fo:list-item-body>
            <fo:block xsl:use-attribute-sets="emphasized-text">
              <xsl:value-of select="."/>
            </fo:block>
          </fo:list-item-body>
        </fo:list-item>
      </xsl:for-each>
    </fo:list-block>
  </xsl:template>

</xsl:stylesheet>

Notice that both the emphasized-text and large-text attribute sets use the regular-text attribute set as a base. In the case of large-text, the font-size attribute defined in the large-text attribute set overrides the font-size attribute included from the regular-text attribute set. We'll apply our stylesheet to the following XML document:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

The stylesheet generates this messy-looking file of formatting objects, which describe how the text of our XML source document should be rendered:

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="main" margin-top="25pt" 
margin-bottom="25pt" page-width="8.5in" page-height="11in" 
margin-left="75pt" margin-right="75pt">
<fo:region-before extent="25pt"/>
<fo:region-body margin-bottom="50pt" margin-top="50pt"/>
<fo:region-after extent="25pt"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="standard">
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference odd-or-even="any" master-name="main"/>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-name="standard">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="18pt" font-family="sans-serif" 
font-weight="bold" space-after.optimum="21pt">A few of my 
favorite albums</fo:block>
<fo:list-block provisional-label-separation="0.15cm" 
provisional-distance-between-starts="0.4cm">
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">A Love Supreme</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">Beat Crazy</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">Here Come the Warm Jets</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">Kind of Blue</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">London Calling</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">Remain in Light</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">The Joshua Tree</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item space-after.optimum="17pt" start-indent="0.5cm">
<fo:list-item-label>
<fo:block font-size="12pt" font-family="sans-serif">*</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block font-size="12pt" font-family="sans-serif" 
font-style="italic">The Indestructible Beat of Soweto</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</fo:flow>
</fo:page-sequence>
</fo:root>

Be aware that as of this writing (May 2001), the XSL-FO specification isn't final, so there's no guarantee that these formatting objects will work correctly with future XSL-FO tools. Here's how we invoke the Apache XML Project's FOP (Formatting Objects to PDF translator) tool to create a PDF:

java org.apache.fop.apps.CommandLine test.fo test.pdf

The FOP tool creates a PDF that looks like Figure A-4.

Figure A-4

Figure A-4. PDF generated from an XSL-FO file

<xsl:call-template>Lets you invoke a particular template by name. This invocation is a convenient way to create commonly used output. For example, if you create an HTML page and all your HTML pages have the same masthead and footer, you could define templates named masthead and footer, then use <xsl:call-template> to invoke those templates as needed.

Category

Instruction

Required Attributes

name
The name of the template you're invoking.

Optional Attributes

None.

Content

This element can contain any number of optional <xsl:with-param> elements.

Appears in

<xsl:call-template> appears inside a template.

Defined in

XSLT section 6, Named Templates.

Example

The <xsl:call-template> element gives you an excellent way to create modular stylesheets. In our case study (see Chapter 9, "Case Study: The Toot-O-Matic"), we need to generate common items at the top and bottom of every HTML page we generate. We build a navigation bar and title bar at the top of each panel in a similar way. Rather than intermingle these templates with the rest of our stylesheets, we put the templates for the common sections of the HTML pages in a separate stylesheet, then reference them when needed.

<xsl:call-template name="dw-masthead"/>
<xsl:call-template name="dw-title-bar"/>
<xsl:call-template name="dw-nav-bar">
  <xsl:with-param name="includeMain" select="'youBetcha'"/>
  <xsl:with-param name="sectionNumber" select="$sectionNumber"/>
  <xsl:with-param name="position" select="$pos"/>
  <xsl:with-param name="last" select="$last"/>
  <xsl:with-param name="topOrBottom" select="'top'"/>
  <xsl:with-param name="oneOrTwo" select="'two'"/>
</xsl:call-template>

<!-- Processing for the main body of the page goes here -->

<xsl:call-template name="dw-nav-bar">
  <xsl:with-param name="includeMain" select="'youBetcha'"/>
  <xsl:with-param name="sectionNumber" select="$sectionNumber"/>
  <xsl:with-param name="position" select="$pos"/>
  <xsl:with-param name="last" select="$last"/>
  <xsl:with-param name="topOrBottom" select="'bottom'"/>
  <xsl:with-param name="oneOrTwo" select="'two'"/>
</xsl:call-template>
<xsl:call-template name="dw-footer"/>

In this code fragment, we've invoked four templates to generate the look and feel we want our HTML pages to have. If we decide to change the look and feel of our tutorials, changing those four named templates lets us change the look and feel by simply transforming the XML document again. See Section 9.5.5, "Generating the Individual Panels" in Chapter 9, "Case Study: The Toot-O-Matic" for details on how this works.

<xsl:choose>The <xsl:choose> element is XSLT's version of the switch or case statement found in many procedural programming languages.

Category

Instruction

Required Attributes

None.

Optional Attributes

None.

Content

Contains one or more <xsl:when> elements and might contain a single <xsl:otherwise> element. Any <xsl:otherwise> elements must be the last element inside <xsl:choose>.

Appears in

<xsl:choose> appears inside a template.

Defined in

XSLT section 9.2, Conditional Processing with xsl:choose.

Example

Here's an example that uses <xsl:choose> to select the background color for the rows of an HTML table. We cycle among four different values, using <xsl:choose> to determine the value of the bgcolor attribute in the generated HTML document. Here's the XML document we'll use:

<?xml version="1.0"?>
<list xml:lang="en">
  <title>Albums I've bought recently:</title>
  <listitem>The Sacred Art of Dub</listitem>
  <listitem>Only the Poor Man Feel It</listitem>
  <listitem>Excitable Boy</listitem>
  <listitem xml:lang="sw">Aki Special</listitem>
  <listitem xml:lang="en-gb">Combat Rock</listitem>
  <listitem xml:lang="zu">Talking Timbuktu</listitem>
  <listitem xml:lang="jz">The Birth of the Cool</listitem>
</list>

And here's our stylesheet:

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

  <xsl:output method="html"/>
 
  <xsl:template match="/">
    <html>
      <head>
        <title>
          <xsl:value-of select="list/title"/>
        </title>
      </head>
      <body>
        <h1><xsl:value-of select="list/title"/></h1>
        <table border="1">
          <xsl:for-each select="list/listitem">
            <tr>
              <td>
                <xsl:attribute name="bgcolor">
                  <xsl:choose>
                    <xsl:when test="position() mod 4 = 0">
                      <xsl:text>papayawhip</xsl:text>
                    </xsl:when>
                    <xsl:when test="position() mod 4 = 1">
                      <xsl:text>mintcream</xsl:text>
                    </xsl:when>
                    <xsl:when test="position() mod 4 = 2">
                      <xsl:text>lavender</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:text>whitesmoke</xsl:text>
                    </xsl:otherwise>
                  </xsl:choose>
                </xsl:attribute>
                <xsl:value-of select="."/>
              </td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

We use <xsl:choose> to determine the background color of each generated <td> element. Here's the generated HTML document, which cycles through the various background colors:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Albums I've bought recently:</title>
</head>
<body>
<h1>Albums I've bought recently:</h1>
<table border="1">
<tr>
<td bgcolor="mintcream">The Sacred Art of Dub</td>
</tr>
<tr>
<td bgcolor="lavender">Only the Poor Man Feel It</td>
</tr>
<tr>
<td bgcolor="whitesmoke">Excitable Boy</td>
</tr>
<tr>
<td bgcolor="papayawhip">Aki Special</td>
</tr>
<tr>
<td bgcolor="mintcream">Combat Rock</td>
</tr>
<tr>
<td bgcolor="lavender">Talking Timbuktu</td>
</tr>
<tr>
<td bgcolor="whitesmoke">The Birth of the Cool</td>
</tr>
</table>
</body>
</html>

When rendered, our HTML document looks like Figure A-5.

Figure A-5

Figure A-5. Document cycling among different background colors

<xsl:comment>Allows you to create a comment in the output document. Comments are sometimes used to add legal notices, disclaimers, or information about when the output document was created. Another useful application of the <xsl:comment> element is the generation of CSS definitions or JavaScript code in an HTML document.

Category

Instruction

Required Attributes

None.

Optional Attributes

None.

Content

An XSLT template.

Appears in

<xsl:comment> appears in a template.

Defined in

XSLT section 7.4, Creating Comments.

Example

Here's a stylesheet that generates a comment to define CSS styles in an HTML document:

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

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>XSLT and CSS Demo</title>
        <style>
          <xsl:comment> 
            p.big      {font-size: 125%; font-weight: bold} 
            p.green    {color: green; font-weight: bold}
            p.red      {color: red; font-style: italic}
          </xsl:comment>
        </style>
      </head>
      <body>
        <xsl:apply-templates select="list/title"/>
        <xsl:apply-templates select="list/listitem"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="title">
    <p class="big"><xsl:value-of select="."/></p>
  </xsl:template>

  <xsl:template match="listitem">
    <xsl:choose>
      <xsl:when test="position() mod 2">
        <p class="green"><xsl:value-of select="."/></p>
      </xsl:when>
      <xsl:otherwise>
        <p class="red"><xsl:value-of select="."/></p>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
</xsl:stylesheet>

This stylesheet creates three CSS styles inside an HTML comment. We'll apply the stylesheet to this document:

<?xml version="1.0"?>
<list xml:lang="en">
  <title>Albums I've bought recently:</title>
  <listitem>The Sacred Art of Dub</listitem>
  <listitem>Only the Poor Man Feel It</listitem>
  <listitem>Excitable Boy</listitem>
  <listitem xml:lang="sw">Aki Special</listitem>
  <listitem xml:lang="en-gb">Combat Rock</listitem>
  <listitem xml:lang="zu">Talking Timbuktu</listitem>
  <listitem xml:lang="jz">The Birth of the Cool</listitem>
</list>

The stylesheet will apply one CSS style to the <title> element and will alternate between two CSS styles for the <listitem>s. Here's the generated HTML:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>XSLT and CSS Demo</title>
<style>
<!-- 
            p.big      {font-size: 125%; font-weight: bold} 
            p.green    {color: green; font-weight: bold}
            p.red      {color: red; font-style: italic}
          -->
</style>
</head>
<body>
<p class="big">Albums I've bought recently:</p>
<p class="green">The Sacred Art of Dub</p>
<p class="red">Only the Poor Man Feel It</p>
<p class="green">Excitable Boy</p>
<p class="red">Aki Special</p>
<p class="green">Combat Rock</p>
<p class="red">Talking Timbuktu</p>
<p class="green">The Birth of the Cool</p>
</body>
</html>

When rendered, the document looks like Figure A-6.

Figure A-6

Figure A-6. Document with generated comment nodes

<xsl:copy>Makes a shallow copy of an element to the result tree. This element only copies the current node and its namespace nodes. The children of the current node and any attributes it has are not copied.

Category

Instruction

Required Attributes

None.

Optional Attributes

use-attribute-sets
Lists one or more attribute sets that should be used by this element. If you specify more than one attribute set, separate their names with whitespace characters. See the description of the <xsl:attribute-set> element for more information.

Content

An XSLT template.

Appears in

<xsl:copy> appears in a template.

Defined in

XSLT section 7.5, Copying.

Example

We'll demonstrate <xsl:copy> with an example that copies an element to the result tree. Notice that we do not specifically request that the attribute nodes of the source document be processed, so the result tree will not contain any attributes. Here is our stylesheet:

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

  <xsl:template match="*">
    <xsl:copy>
      <xsl:apply-templates/>

    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

We'll test our stylesheet with the following XML document:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

Here are the results:

<?xml version="1.0" encoding="UTF-8"?>
<report>
  <title>Miles Flown in 2001</title>
  <month>
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month>
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month>
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month>
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

The <xsl:copy> does a shallow copy, which gives you more control over the output than the <xsl:copy-of> element does. However, you must explicitly specify any child nodes or attribute nodes you would like copied to the result tree. The <xsl:apply-templates> element selects all text, element, comment, and processing-instruction children of the current element; without this element, the result tree would contain only a single, empty <report> element. Compare this approach with the example in the <xsl:copy-of> element.

<xsl:copy-of>Copies things to the result tree. The select attribute defines the content to be copied. If the select attribute identifies a result-tree fragment, the complete fragment is copied to the result tree. If select identifies a node-set, all nodes in the node-set are copied to the result tree in document order; unlike <xsl:copy>, the node is copied in its entirety, including any namespace nodes, attribute nodes, and child nodes. If the select attribute identifies something other than a result-tree fragment or a node-set, it is converted to a string and inserted into the result tree.

Category

Instruction

Required Attributes

select
Contains an XPath expression that defines the nodes to be copied to the output document.

Optional Attributes

None.

Content

None. <xsl:copy-of> is an empty element.

Appears in

<xsl:copy-of> appears inside a template.

Defined in

XSLT section 11.3, Using Values of Variables and Parameters with xsl:copy-of.

Example

We'll demonstrate <xsl:copy-of> with a simple stylesheet that copies the input document to the result tree. Here is our stylesheet:

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


  <xsl:template match="/">
    <xsl:copy-of select="."/>
  </xsl:template>

</xsl:stylesheet>

We'll test our stylesheet with the following document:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

When we transform the XML document, the results are strikingly similar to the input document:

<?xml version="1.0" encoding="UTF-8"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

The only difference between the two documents is that the stylesheet engine has added an encoding to the XML declaration. Compare this to the example in the <xsl:copy> element.

<xsl:decimal-format>Defines a number format to be used when writing numeric values to the output document. If the <decimal-format> does not have a name, it is assumed to be the default number format used for all output. On the other hand, if a number format is named, it can be referenced from the format-number() function.

Category

Top-level element

Required Attributes

None.

Optional Attributes

name
Gives a name to this format.

decimal-separator
Defines the character (usually either a period or comma) used as the decimal point. This character is used both in the format string and in the output. The default value is the period character (.).

grouping-separator
Defines the character (usually either a period or comma) used as the thousands separator. This character is used both in the format string and in the output. The default value is the comma (,).

infinity
Defines the string used to represent infinity. Be aware that XSLT's number facilities support both positive and negative infinity. This string is used only in the output. The default value is the string "Infinity".

minus-sign
Defines the character used as the minus sign. This character is used only in the output. The default value is the hyphen character (-, #x2D).

NaN
Defines the string displayed when the value to be formatted is not a number. This string is used only in the output; the default value is the string "NaN".

percent
Defines the character used as the percent sign. This character is used both in the format string and in the output. The default value is the percent sign (%).

per-mille
Defines the character used as the per-mille sign. This character is used both in the format string and in the output. The default value is the Unicode per-mille character (#x2030).

zero-digit
Defines the character used for the digit zero. This character is used both in the format string and in the output. The default is the digit zero (0).

digit
Defines the character used in the format string to stand for a digit. The default is the number sign character (#).

pattern-separator
Defines the character used to separate the positive and negative subpatterns in a pattern. The default value is the semicolon (;). This character is used only in the format string.

Content

None. <xsl:decimal-format> is an empty element.

Appears in

<xsl:decimal-format> is a top-level element and can only appear as a child of <xsl:stylesheet>.

Defined in

XSLT section 12.3, Number Formatting.

Example

Here is a stylesheet that defines two <decimal-format>s:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <xsl:output method="text"/>

  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>

  <xsl:decimal-format name="f1"
    decimal-separator=":"
    grouping-separator="/"/>

  <xsl:decimal-format name="f2"
    infinity="Really, really big"
    NaN="[not a number]"/>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:text>Tests of the <decimal-format> element:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(1528.3, '#/###:00', 'f1')=</xsl:text>
    <xsl:value-of select="format-number(1528.3, '#/###:00;-#/###:00', 'f1')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(1 div 0, '###,###.00', 'f2')=</xsl:text>
    <xsl:value-of select="format-number(1 div 0, '###,###.00', 'f2')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(blue div orange, '#.##', 'f2')=</xsl:text>
    <xsl:value-of select="format-number(blue div orange, '#.##', 'f2')"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=current()/@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>     (</xsl:text>
      <xsl:value-of 
        select="format-number(miles-flown div sum(//miles-flown), '##%')"/>
      <xsl:text> of all miles flown, </xsl:text>
      <xsl:value-of 
        select="format-number(miles-earned div sum(//miles-earned), '##%')"/>
      <xsl:text> of all miles earned.)</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each> 
    <xsl:text>   Total miles flown: </xsl:text>
    <xsl:value-of select="format-number(sum(//miles-flown), '##,###')"/>
    <xsl:text>, total miles earned: </xsl:text>
    <xsl:value-of select="format-number(sum(//miles-earned), '##,###')"/>
  </xsl:template>

</xsl:stylesheet>

We'll use this stylesheet against the following document:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

When we process this document with the stylesheet, here are the results:


Tests of the <decimal-format> element:

   format-number(1528.3, '#/###:00', 'f1')=1/528:30
   format-number(1 div 0, '###,###.00', 'f2')=Really, really big
   format-number(blue div orange, '#.##', 'f2')=[not a number]

   January - 12,379 miles flown, 35,215 miles earned.
     (15% of all miles flown, 15% of all miles earned.)

   February - 32,857 miles flown, 92,731 miles earned.
     (39% of all miles flown, 39% of all miles earned.)

   March - 19,920 miles flown, 76,725 miles earned.
     (24% of all miles flown, 32% of all miles earned.)

   April - 18,903 miles flown, 31,781 miles earned.
     (22% of all miles flown, 13% of all miles earned.)

   Total miles flown: 84,059, total miles earned: 236,452
<xsl:element>Allows you to create an element in the output document. It works similarly to the <xsl:attribute> element.

Category

Instruction

Required Attributes

name
Defines the name of this element. A value of name="fred" will produce a <fred> element in the output document.

Optional Attributes

namespace
Defines the namespace used for this attribute.

use-attribute-sets
Lists one or more attribute sets that should be used by this element. If you specify more than one attribute set, separate their names with whitespace characters.

Content

An XSLT template.

Appears in

<xsl:element> appears inside a template.

Defined in

XSLT section 7.1.2, Creating Elements with xsl:element.

Example

We'll use a generic stylesheet that copies the input document to the result tree, with one exception: all attributes in the original documents are converted to child elements in the result tree. The name of the new element will be the name of the format attribute, and its text will be the value of the attribute. Because we don't know the name of the attribute until we process the XML source document, we must use the <xsl:element> element to create the result tree. Here's how our stylesheet looks:

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

  <xsl:template match="*">
    <xsl:element name="{name()}">
      <xsl:for-each select="@*">
        <xsl:element name="{name()}">
          <xsl:value-of select="."/>
        </xsl:element>
      </xsl:for-each>
      <xsl:apply-templates select="*|text()"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

This stylesheet uses the <xsl:element> element in two places: first to create a new element with the same name as the original element, and second to create a new element with the same name as each attribute. We'll apply the stylesheet to this document:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

Here are our results:

<?xml version="1.0" encoding="UTF-8"?>
<report>
  <title>Miles Flown in 2001</title>
  <month><sequence>01</sequence>
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month><sequence>02</sequence>
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month><sequence>03</sequence>
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month><sequence>04</sequence>
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

The <xsl:element> element created all the elements in the output document, including the <sequence> elements that were created from the sequence attributes in the original document.

<xsl:fallback>Defines a template that should be used when an extension element can't be found.

Category

Instruction

Required Attributes

None.

Optional Attributes

None.

Content

An XSLT template.

Appears in

<xsl:fallback> appears inside a template.

Defined in

XSLT section 15, Fallback.

Example

Here is a stylesheet that uses <xsl:fallback> to terminate the transformation if an extension element can't be found:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:db="xalan://DatabaseExtension"
  extension-element-prefixes="db">

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title><xsl:value-of select="report/title"/></title>
      </head>
      <body>
        <h1><xsl:value-of select="report/title"/></h1>
        <xsl:for-each select="report/section">
          <h2><xsl:value-of select="title"/></h2>
          <xsl:for-each select="dbaccess">
            <db:accessDatabase>
              <xsl:fallback>
                <xsl:message terminate="yes">
                  Database library not available!
                </xsl:message>
              </xsl:fallback> 
            </db:accessDatabase>
          </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

When we use this stylesheet to transform a document, the <xsl:fallback> element is processed if the extension element can't be found:


Database library not available!

Processing terminated using xsl:message

In this case, the extension element is the Java class DatabaseExtension. If, for whatever reason, that class can't be loaded, the <xsl:fallback> element is processed. Note that the <xsl:fallback> element is processed only when the extension element can't be found; if the code that implements that extension element is found, but fails, it must be handled some other way. Also be aware that the exact format of the message and the gracefulness of stylesheet termination will vary from one XSLT processor to the next.

<xsl:for-each>Acts as XSLT's iteration operator. This element has a select attribute that selects some nodes from the current context.

Category

Instruction

Required Attributes

select
Contains an XPath expression that selects nodes from the current context.

Optional Attributes

None.

Content

<xsl:for-each> contains a template that is evaluated against each of the selected nodes. The <xsl:for-each> element can contain one or more <xsl:sort> elements to order the selected nodes before they are processed. All <xsl:sort> elements must appear first, before the template begins.

Appears in

<xsl:for-each> appears inside a template.

Defined in

XSLT section 8, Repetition.

Example

We'll demonstrate the <xsl:for-each> element with the following stylesheet:

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

  <xsl:output method="text"/>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>

  <xsl:variable name="complicatedVariable">
    <xsl:choose>
      <xsl:when test="count(//listitem) > 10">
        <xsl:text>really long list</xsl:text>
      </xsl:when>
      <xsl:when test="count(//listitem) > 5">
        <xsl:text>moderately long list</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>fairly short list</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:text>Here is a </xsl:text>
    <xsl:value-of select="$complicatedVariable"/>
    <xsl:text>:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:variable name="listitems" select="list/listitem"/>
    <xsl:call-template name="processListitems">
      <xsl:with-param name="items" select="$listitems"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="processListitems">
    <xsl:param name="items"/>
    <xsl:for-each select="$items">
      <xsl:value-of select="position()"/>
      <xsl:text>.  </xsl:text>
      <xsl:value-of select="."/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

In this stylesheet, we use an <xsl:param> named items to illustrate the <xsl:for-each> element. The items parameter contains some number of <listitem> elements from the XML source document; the <xsl:for-each> element iterates through all those elements and processes each one. We'll use our stylesheet with the following XML document:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

When we run the transformation, here are the results:

Here is a moderately long list:
1.  A Love Supreme
2.  Beat Crazy
3.  Here Come the Warm Jets
4.  Kind of Blue
5.  London Calling
6.  Remain in Light
7.  The Joshua Tree
8.  The Indestructible Beat of Soweto

The <xsl:for-each> element has iterated through all the <listitem> elements from the XML source document and has processed each one.

<xsl:if>Implements an if statement. It contains a test attribute and an XSLT template. If the test attribute evaluates to the boolean value true, the XSLT template is processed. This element implements an if statement only; if you need an if-then-else statement, use the <xsl:choose> element with a single <xsl:when> and a single <xsl:otherwise>.

Category

Instruction

Required Attributes

test
The test attribute contains a boolean expression. If it evaluates to the boolean value true, then the XSLT template inside the <xsl:if> element is processed.

Optional Attributes

None.

Content

An XSLT template.

Appears in

<xsl:if> appears inside a template.

Defined in

XSLT section 9.1, Conditional Processing with xsl:if.

Example

We'll illustrate the <xsl:if> element with the following stylesheet:

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

  <xsl:output method="text"/>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:text>Here are the odd-numbered items from the list:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="list/listitem">
      <xsl:if test="(position() mod 2) = 1">
        <xsl:number format="1. "/>
        <xsl:value-of select="."/>
        <xsl:value-of select="$newline"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
  
</xsl:stylesheet>

This stylesheet uses the <xsl:if> element to see if a given <listitem>'s position is an odd number. If it is, we write it to the result tree. We'll test our stylesheet with this XML document:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

When we run this transformation, here are the results:

Here are the odd-numbered items from the list:
1. A Love Supreme
3. Here Come the Warm Jets
5. London Calling
7. The Joshua Tree
<xsl:import>Allows you to import the templates found in another XSLT stylesheet. Unlike <xsl:include>, all templates imported with <xsl:import> have a lower priority than those in the including stylesheet. Another difference between <xsl:include> and <xsl:import> is that <xsl:include> can appear anywhere in a stylesheet, while <xsl:import> can appear only at the beginning.

Category

Top-level element

Required Attributes

href
Defines the URI of the imported stylesheet.

Optional Attributes

None.

Content

None. <xsl:import> is an empty element.

Appears in

<xsl:import> is a top-level element and can appear only as a child of <xsl:stylesheet>.

Defined in

XSLT section 2.6.2, Stylesheet Import.

Example

Here is a simple stylesheet that we'll import:

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

  <xsl:output method="text"/>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>


  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:apply-templates select="list/title"/>
    <xsl:apply-templates select="list/listitem"/>
  </xsl:template>

  <xsl:template match="title">
    <xsl:value-of select="."/>
    <xsl:text>: </xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="listitem">
    <xsl:text>HERE IS LISTITEM NUMBER </xsl:text>
    <xsl:value-of select="position()"/>
    <xsl:text>:  </xsl:text>
    <xsl:value-of select="."/>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

We'll test both this stylesheet and the one that imports it with this XML document:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

When we process our XML source document with this stylesheet, here are the results:

A few of my favorite albums:

HERE IS LISTITEM NUMBER 1:  A Love Supreme
HERE IS LISTITEM NUMBER 2:  Beat Crazy
HERE IS LISTITEM NUMBER 3:  Here Come the Warm Jets
HERE IS LISTITEM NUMBER 4:  Kind of Blue
HERE IS LISTITEM NUMBER 5:  London Calling
HERE IS LISTITEM NUMBER 6:  Remain in Light
HERE IS LISTITEM NUMBER 7:  The Joshua Tree
HERE IS LISTITEM NUMBER 8:  The Indestructible Beat of Soweto

Now we'll use <xsl:import> in another stylesheet:

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

  <xsl:import href="listitem.xsl"/>

  <xsl:output method="text"/>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:apply-templates select="list/title"/>
    <xsl:apply-templates select="list/listitem"/>
  </xsl:template>

  <xsl:template match="listitem">
    <xsl:value-of select="position()"/>
    <xsl:text>.  </xsl:text>
    <xsl:value-of select="."/>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

Here are the results created by our second stylesheet:

A few of my favorite albums:

1.  A Love Supreme
2.  Beat Crazy
3.  Here Come the Warm Jets
4.  Kind of Blue
5.  London Calling
6.  Remain in Light
7.  The Joshua Tree
8.  The Indestructible Beat of Soweto

Notice that both stylesheets had a template with match="listitem". The template in the imported stylesheet has a lower priority, so it is not used. Only the imported stylesheet has a template with match="title", so the imported template is used for the <title> element.

<xsl:include>Allows you to include another XSLT stylesheet. This element allows you to put common transformations in a separate stylesheet, then include the templates from that stylesheet at any time. Unlike <xsl:import>, all templates included with <xsl:include> have the same priority as those in the including stylesheet. Another difference is that <xsl:include> can appear anywhere in a stylesheet, while <xsl:import> must appear at the beginning.

Category

Top-level element

Required Attributes

href
Defines the URI of the included stylesheet.

Optional Attributes

None.

Content

None. <xsl:include> is an empty element.

Appears in

<xsl:include> is a top-level element and can appear only as a child of <xsl:stylesheet>.

Defined in

XSLT section 2.6.1, Stylesheet Inclusion.

Example

The <xsl:include> element is a good way to break your stylesheets into smaller pieces. (Those smaller pieces are often easier to reuse.) In our case study (see Chapter 9, "Case Study: The Toot-O-Matic"), we had a number of different stylesheets, each of which contained templates for a particular purpose. Here's how our <xsl:include> elements look:

<xsl:include href="toot-o-matic-variables.xsl"/>

<xsl:include href="xslt-utilities.xsl"/>
<xsl:include href="dw-style.xsl"/>

<xsl:include href="build-main-index.xsl"/>
<xsl:include href="build-section-indexes.xsl"/>
<xsl:include href="build-individual-panels.xsl"/>
<xsl:include href="build-graphics.xsl"/>
<xsl:include href="build-pdf-file.xsl"/>
<xsl:include href="build-zip-file.xsl"/>

Segmenting your stylesheets this way can make debugging simpler, as well. In our example here, all the rules for creating a PDF file are in the stylesheet build-pdf-file.xsl. If the PDF files are not built correctly, build-pdf-file.xsl is most likely the source of the problem. All visual elements of our generated HTML pages are created in the stylesheet dw-style.xsl. If we need to change the look of all the HTML pages, changing the templates in dw-style.xsl will do the trick.

<xsl:key>Defines an index against the current document. The element is defined with three attributes: a name, which names this index; a match, an XPath expression that describes the nodes to be indexed; and a use attribute, an XPath expression that defines the property used to create the index.

Category

Top-level element

Required Attributes

name
Defines a name for this key.

match
Represents an XPath expression that defines the nodes to be indexed by this key.

use
Represents an XPath expression that defines the property of the indexed nodes that will be used to retrieve nodes from the index.

Optional Attributes

None.

Content

None. <xsl:key> is an empty element.

Appears in

<xsl:key> is a top-level element and can only appear as a child of <xsl:stylesheet>.

Defined in

XSLT section 12.2, Keys.

Example

Here is a stylesheet that defines two <xsl:key> relations against an XML document:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*"/>

  <xsl:key name="language-index" match="defn" use="@language"/>
  <xsl:key name="term-ids"       match="term" use="@id"/>

  <xsl:param name="targetLanguage"/>

  <xsl:template match="/">
    <xsl:apply-templates select="glossary"/>
  </xsl:template>

  <xsl:template match="glossary">
    <html>
      <head>
        <title>
          <xsl:text>Glossary Listing: </xsl:text>
          <xsl:value-of select="key('language-index', 
        $targetLanguage)[1]/preceding-sibling::term"/>
          <xsl:text> - </xsl:text>
          <xsl:value-of select="key('language-index', 
        $targetLanguage)[last()]/preceding-sibling::term"/>
        </title>
      </head>
      <body>
        <h1>
          <xsl:text>Glossary Listing: </xsl:text>
          <xsl:value-of select="key('language-index', 
        $targetLanguage)[1]/ancestor::glentry/term"/>
          <xsl:text> - </xsl:text>
          <xsl:value-of select="key('language-index', 
        $targetLanguage)[last()]/ancestor::glentry/term"/>
        </h1>
        <xsl:for-each select="key('language-index', $targetLanguage)">
          <xsl:apply-templates select="ancestor::glentry"/>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

  ...

</xsl:stylesheet>

For a complete discussion of this stylesheet, illustrating how the <xsl:key> relations are used, see Section 5.2.3, "Stylesheets That Use the key() Function" in Chapter 5, "Creating Links and Cross-References".

<xsl:message>Sends a message. How the message is sent can vary from one XSLT processor to the next, but it's typically written to the standard output device. This element is useful for debugging stylesheets.

Category

Instruction

Required Attributes

None.

Optional Attributes

terminate="yes"|"no"
If this attribute has the value yes, the XSLT processor stops execution after issuing this message. The default value for this attribute is no; if the <xsl:message> doesn't terminate the processor, the message is sent and processing continues.

Content

An XSLT template.

Appears in

<xsl:message> appears inside a template.

Defined in

XSLT section 13, Messages.

Example

Here's a stylesheet that uses the <xsl:message> element to trace the transformation of an XML document. We'll use our list of recently purchased albums again:

<?xml version="1.0"?>
<list xml:lang="en">
  <title>Albums I've bought recently:</title>
  <listitem>The Sacred Art of Dub</listitem>
  <listitem>Only the Poor Man Feel It</listitem>
  <listitem>Excitable Boy</listitem>
  <listitem xml:lang="sw">Aki Special</listitem>
  <listitem xml:lang="en-gb">Combat Rock</listitem>
  <listitem xml:lang="zu">Talking Timbuktu</listitem>
  <listitem xml:lang="jz">The Birth of the Cool</listitem>
</list>

We'll list all of the purchased albums in an HTML table, with the background color of each row alternating through various colors. Our stylesheet uses an <xsl:choose> element inside an <xsl:attribute> element to determine the value of the bgcolor attribute. If a given <listitem> is converted to an HTML <tr> with a background color of lavender, we'll issue a celebratory message:

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

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>
          <xsl:value-of select="list/title"/>
        </title>
      </head>
      <body>
        <h1><xsl:value-of select="list/title"/></h1>
        <table border="1">
          <xsl:for-each select="list/listitem">
            <tr>
              <td>
                <xsl:attribute name="bgcolor">
                  <xsl:choose>
                    <xsl:when test="position() mod 4 = 0">
                      <xsl:text>papayawhip</xsl:text>
                    </xsl:when>
                    <xsl:when test="position() mod 4 = 1">
                      <xsl:text>mintcream</xsl:text>
                    </xsl:when>
                    <xsl:when test="position() mod 4 = 2">
                      <xsl:text>lavender</xsl:text>
                      <xsl:message terminate="no">
                        <xsl:text>Table row #</xsl:text>
                        <xsl:value-of select="position()"/>
                        <xsl:text> is lavender!</xsl:text>
                      </xsl:message>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:text>whitesmoke</xsl:text>
                    </xsl:otherwise>
                  </xsl:choose>
                </xsl:attribute>
                <xsl:value-of select="."/>
              </td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Note that the XSLT specification doesn't define how the message is issued. When we use this stylesheet with Xalan 2.0.1, we get these results:

file:///D:/O'Reilly/XSLT/bookSamples/AppendixA/message.xsl; Line 32; Column 51;
Table row #2 is lavender!
file:///D:/O'Reilly/XSLT/bookSamples/AppendixA/message.xsl; Line 32; Column 51;
Table row #6 is lavender!

Xalan gives us feedback on the part of the stylesheet that generated each message. Saxon, on the other hand, keeps things short and sweet:

Table row #2 is lavender!
Table row #6 is lavender!

For variety's sake, here's how XT processes the <xsl:message> element:

file:/D:/O'Reilly/XSLT/bookSamples/AppendixA/test4.xml:5: Table row #2 is lavender!
file:/D:/O'Reilly/XSLT/bookSamples/AppendixA/test4.xml:9: Table row #6 is lavender!

XT gives information about the line in the XML source document that generated the message.

<xsl:namespace-alias>Allows you to define an alias for a namespace when using the namespace directly would complicate processing. This seldom-used element is the simplest way to write a stylesheet that generates another stylesheet.

Category

Top-level element

Required Attributes

stylesheet-prefix
Defines the prefix used in the stylesheet to refer to the namespace.

result-prefix
Defines the prefix for the namespace referred to by the alias. This prefix must be declared in the stylesheet, regardless of whether any elements in the stylesheet use it.

Optional Attributes

None.

Content

None. <xsl:namespace-alias> is an empty element.

Appears in

<xsl:stylesheet>. <xsl:namespace-alias> is a top-level element and can appear only as a child of <xsl:stylesheet>.

Defined in

XSLT section 7.1.1, Literal Result Elements.

Example

This element is not used frequently, and the reasons for its existence are based on the somewhat obscure case of an XSLT stylesheet that needs to generate another XSLT stylesheet. Our test case here creates a stylesheet that generates the identity transform, a stylesheet that simply copies any input document to the result tree. Here's our original stylesheet that uses the namespace alias:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xslout="(the namespace URI doesn't matter here)">

  <xsl:output method="xml" indent="yes"/>
 
  <xsl:namespace-alias stylesheet-prefix="xslout"
    result-prefix="xsl"/>

  <xsl:template match="/">
    <xslout:stylesheet version="1.0">
      <xslout:output method="xml"/>
      <xslout:template match="/">
        <xslout:copy-of select="."/>
      </xslout:template>
    </xslout:stylesheet>
  </xsl:template>

</xsl:stylesheet>

When we run this stylesheet with any XML document at all, we get a new stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xslout:stylesheet xmlns:xslout="http://www.w3.org/1999/XSL/Transform" 
  version="1.0">
<xslout:output method="xml"/>
<xslout:template match="/">
<xslout:copy-of select="."/>
</xslout:template>
</xslout:stylesheet>

You can take this generated stylesheet and use it to copy any XML document. In our original stylesheet, we use an <xsl:namespace-alias> because we have no other way of identifying to the XSLT processor with which XSLT elements should be processed and which ones should be treated as literals passed to the output. Using the namespace alias lets us generate the XSLT elements we need in our output. Notice in the result document that the correct namespace value was declared automatically on the <xslout:stylesheet> element.

<xsl:number>Counts something. It is most often used to number parts of a document, although it can also be used to format a numeric value.

Category

Instruction

Required Attributes

None.

Optional Attributes

count
The count attribute is an XPath expression that defines what should be counted.

level
This attribute defines what levels of the source tree should be considered when numbering elements. The three valid values for this attribute are single, multiple, and any:

single
Counts items at one level only. The XSLT processor goes to the first node in the ancestor-or-self axis that matches the count attribute, then counts that node plus all its preceding siblings that also match the count attribute.

multiple
Counts items at multiple levels. The XSLT processor looks at all ancestors of the current node and the current node itself, then it selects all of those nodes that match the count attribute.

any
Includes all of the current node's ancestors (as level="multiple" does) as well as all elements in the preceding axis.

In all of these cases, if the from attribute is used, the only ancestors that are examined are descendants of the nearest ancestor that matches the from attribute. In other words, with from="h1", the only nodes considered for counting are those that appear under the nearest <h1> attribute.

from
The from attribute is an XPath expression that defines where counting starts. For example, you can use the from attribute to say that counting should begin at the previous <h1> element.

value
An expression that is converted to a number. Using this attribute is a quick way to format a number; the element <xsl:number value="7" format="i:"/> returns the string "vii:".

format
The format attribute defines the format of the generated number:

format="1"
Formats a sequence of numbers as 1 2 3 4 5 6 7 8 9 10 11 ....

format="01"
Formats a sequence of numbers as 01 02 03 04 ... 09 10 11 ... 99 100 101 ....

format="a"
Formats a sequence of numbers as a b c d e f ... x y z aa ab ac ....

format="A"
Formats a sequence of numbers as A B C D E F ... X Y Z AA AB AC ....

format="i"
Formats a sequence of numbers as i ii iii iv v vi vii viii ix x ....

format="I"
Formats a sequence of numbers as I II III IV V VI VII VIII IX X ....

format="anything else"
How this works is depends on the XSLT processor you're using. The XSLT specification lists several other numbering schemes (Thai digits, Katakana numbering, traditional Hebrew numbering, etc.); check your XSLT processor's documentation to see which formats it supports. If the XSLT processor doesn't support the numbering scheme you requested, the XSLT spec requires that it use format="1" as the default.

lang
The lang attribute defines the language whose alphabet should be used. Different XSLT processors support different language values, so check the documentation of your favorite XSLT processor for more information.

letter-value
This attribute has the value alphabetic or traditional. There are a number of languages in which two letter-based numbering schemes are used; one assigns numeric values in alphabetic sequence, while the other uses a tradition native to that language. (Roman numerals -- a letter-based numbering scheme that doesn't use an alphabetic order -- are one example.) The default for this attribute is alphabetic.

grouping-separator
This attribute is the character that should be used between groups of digits in a generated number. The default is the comma (,).

grouping-size
This attribute defines the number of digits that appear in each group; the default is 3.

Content

None. <xsl:number> is an empty element.

Appears in

<xsl:number> appears inside a template.

Defined in

XSLT section 7.7, Numbering.

Example

To fully illustrate how <xsl:number> works, we'll need an XML document with many things to count. Here's the document we'll use:

<?xml version="1.0"?>
<book>
  <chapter>
    <title>Alfa Romeo</title>
    <sect1>
      <title>Bentley</title>
    </sect1>
    <sect1>
      <title>Chevrolet</title>
      <sect2>
        <title>Dodge</title>
        <sect3>
          <title>Eagle</title>
        </sect3>
      </sect2>
    </sect1>
  </chapter>
  <chapter>
    <title>Ford</title>
    <sect1>
      <title>GMC</title>
      <sect2>
        <title>Honda</title>
        <sect3>
          <title>Isuzu</title>
        </sect3>
        <sect3>
          <title>Javelin</title>
        </sect3>
        <sect3>
          <title>K-Car</title>
        </sect3>
        <sect3>
          <title>Lincoln</title>
        </sect3>
      </sect2>
      <sect2>
        <title>Mercedes</title>
      </sect2>
      <sect2>
        <title>Nash</title>
        <sect3>
          <title>Opel</title>
        </sect3>
        <sect3>
          <title>Pontiac</title>
        </sect3>
      </sect2>
      <sect2>
        <title>Quantum</title>
        <sect3>
          <title>Rambler</title>
        </sect3>
        <sect3>
          <title>Studebaker</title>
        </sect3>
      </sect2>
    </sect1>
    <sect1>
      <title>Toyota</title>
      <sect2>
        <title>Um, is there a car that starts with "U"?</title>
      </sect2>
    </sect1>
    <sect1>
      <title>Volkswagen</title>
    </sect1>
  </chapter>
</book>

We'll use <xsl:number> in several different ways to illustrate the various options we have in numbering things. We'll look at the stylesheet and the results, then we'll discuss them. Here's the stylesheet:

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

  <xsl:output method="text"/>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:apply-templates select="book" mode="number-1"/>
    <xsl:apply-templates select="book" mode="number-2"/>
    <xsl:apply-templates select="book" mode="number-3"/>
    <xsl:apply-templates select="book" mode="number-4"/>
    <xsl:apply-templates select="book" mode="number-5"/>
    <xsl:apply-templates select="book" mode="number-6"/>

    <xsl:apply-templates select="book" mode="number-7"/>
  </xsl:template>

  <xsl:template match="book" mode="number-1">
    <xsl:text>Test #1: level="multiple", 
         count="chapter|sect1|sect2|sect3", 
         format="1.1.1.1. "</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
      <xsl:number level="multiple" count="chapter|sect1|sect2|sect3"
        format="1.1.1.1. "/>
        <xsl:value-of select="title"/>
        <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="book" mode="number-2">
    <xsl:text>Test #2: level="any", 
         count="chapter|sect1|sect2|sect3", 
         format="1. "</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
      <xsl:number level="any" count="chapter|sect1|sect2|sect3"
        format="1. "/>
        <xsl:value-of select="title"/>
        <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="book" mode="number-3">
    <xsl:text>Test #3: level="single", 
         count="chapter|sect1|sect2|sect3", 
         format="1.1.1.1. "</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
      <xsl:number level="single" count="chapter|sect1|sect2|sect3"
        format="1.1.1.1. "/>
        <xsl:value-of select="title"/>
        <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>


  <xsl:template match="book" mode="number-4">
    <xsl:text>Test #4: level="multiple", 
         select=".//sect2",
         count="chapter|sect1|sect2", 
         format="I-A-i: "</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select=".//sect2">
      <xsl:number level="multiple" count="chapter|sect1|sect2"
        format="I-A-i: "/>
        <xsl:value-of select="title"/>
        <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="book" mode="number-5">
    <xsl:text>Test #5: level="any", 
         count="[various elements]"
         from="[various elements]"
         format="1.1.1.1. "</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select=".//sect3">
      <xsl:number level="any" from="book" count="chapter" format="1."/>
      <xsl:number level="any" from="chapter" count="sect1" format="1."/>
      <xsl:number level="any" from="sect1" count="sect2" format="1."/>
      <xsl:number level="any" from="sect2" count="sect3" format="1. "/>
      <xsl:value-of select="title"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="book" mode="number-6">
    <xsl:text>Test #6: level="any", 
         count="chapter|sect1|sect2|sect3",
         grouping-separator=",",
         using a variable to start counting at 1000.</xsl:text> 
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
      <xsl:variable name="value1">
        <xsl:number level="any" count="chapter|sect1|sect2|sect3"/>
      </xsl:variable>
      <xsl:number value="$value1 + 999"
        grouping-separator="." grouping-size="3"/>
      <xsl:text>. </xsl:text>
      <xsl:value-of select="title"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="book" mode="number-7">
    <xsl:text>Test #7: level="multiple", 
         count="chapter|sect1|sect2|sect3", 
         format="1.1.1.1. ",
         selecting up to the first two <sect1> elements from chapter 2.</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="chapter[2]/sect1[position() < 3]">
      <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
        <xsl:number level="multiple" count="chapter|sect1|sect2|sect3"
          format="1.1.1.1. "/>
        <xsl:value-of select="title"/>
        <xsl:value-of select="$newline"/>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here are our results:


Test #1: level="multiple", 
         count="chapter|sect1|sect2|sect3", 
         format="1.1.1.1. "

1. Alfa Romeo
1.1. Bentley
1.2. Chevrolet
1.2.1. Dodge
1.2.1.1. Eagle
2. Ford
2.1. GMC
2.1.1. Honda
2.1.1.1. Isuzu
2.1.1.2. Javelin
2.1.1.3. K-Car
2.1.1.4. Lincoln
2.1.2. Mercedes
2.1.3. Nash
2.1.3.1. Opel
2.1.3.2. Pontiac
2.1.4. Quantum
2.1.4.1. Rambler
2.1.4.2. Studebaker
2.2. Toyota

2.2.1. Um, is there a car that starts with "U"?
2.3. Volkswagen

Test #2: level="any", 
         count="chapter|sect1|sect2|sect3", 
         format="1. "

1. Alfa Romeo
2. Bentley
3. Chevrolet
4. Dodge
5. Eagle
6. Ford
7. GMC
8. Honda
9. Isuzu
10. Javelin
11. K-Car
12. Lincoln
13. Mercedes
14. Nash
15. Opel
16. Pontiac
17. Quantum
18. Rambler
19. Studebaker
20. Toyota
21. Um, is there a car that starts with "U"?
22. Volkswagen

Test #3: level="single", 
         count="chapter|sect1|sect2|sect3", 
         format="1.1.1.1. "

1. Alfa Romeo
1. Bentley
2. Chevrolet
1. Dodge
1. Eagle
2. Ford
1. GMC
1. Honda
1. Isuzu
2. Javelin
3. K-Car
4. Lincoln
2. Mercedes
3. Nash
1. Opel
2. Pontiac
4. Quantum
1. Rambler
2. Studebaker
2. Toyota
1. Um, is there a car that starts with "U"?
3. Volkswagen

Test #4: level="multiple", 
         select=".//sect2",
         count="chapter|sect1|sect2", 
         format="I-A-i: "

I-B-i: Dodge
II-A-i: Honda
II-A-ii: Mercedes
II-A-iii: Nash
II-A-iv: Quantum
II-B-i: Um, is there a car that starts with "U"?

Test #5: level="any", 
         count="[various elements]"
         from="[various elements]"
         format="1.1.1.1. "

1.2.1.1. Eagle
2.1.1.1. Isuzu
2.1.1.2. Javelin
2.1.1.3. K-Car
2.1.1.4. Lincoln
2.1.3.1. Opel
2.1.3.2. Pontiac
2.1.4.1. Rambler
2.1.4.2. Studebaker

Test #6: level="any", 
         count="chapter|sect1|sect2|sect3",
         grouping-separator=",",
         using a variable to start counting at 1000.

1,000. Alfa Romeo
1,001. Bentley
1,002. Chevrolet
1,003. Dodge
1,004. Eagle
1,005. Ford
1,006. GMC
1,007. Honda
1,008. Isuzu
1,009. Javelin
1,010. K-Car
1,011. Lincoln
1,012. Mercedes
1,013. Nash
1,014. Opel
1,015. Pontiac
1,016. Quantum
1,017. Rambler
1,018. Studebaker
1,019. Toyota
1,020. Um, is there a car that starts with "U"?
1,021. Volkswagen

Test #7: level="multiple", 
         count="chapter|sect1|sect2|sect3", 
         format="1.1.1.1. ",
         selecting up to the first two <sect1> elements from chapter 2.

2.1. GMC
2.1.1. Honda
2.1.1.1. Isuzu
2.1.1.2. Javelin
2.1.1.3. K-Car
2.1.1.4. Lincoln
2.1.2. Mercedes
2.1.3. Nash
2.1.3.1. Opel
2.1.3.2. Pontiac
2.1.4. Quantum
2.1.4.1. Rambler
2.1.4.2. Studebaker
2.2. Toyota
2.2.1. Um, is there a car that starts with "U"?

In Test 1, we used level="multiple" to count the <chapter>, <sect1>, <sect2>, and <sect3> elements. Numbering these at multiple levels gives us a dotted-decimal number for each element. We can look at the number next to Studebaker and know that it is the second <sect3> element inside the fourth <sect2> element inside the first <sect1> element inside the second <chapter> element.

Test 2 uses level="any" to count all of the <chapter>, <sect1>, <sect2>, and <sect3> elements in order.

Test 3 uses level="single" to count the elements at each level. This means that the fourth <sect3> element inside a given <sect2> element will be numbered with a 4 (or iv or D or whatever the appropriate value would be). Notice that the number used for each element is the same as the last number beside each element in Test 1.

Test 4 does a couple of things differently: first, it uses the uppercase-alpha and lowercase-roman numbering styles. Second, it counts elements at multiple levels (for the <chapter>, <sect1>, and <sect2> elements), but we only process the <sect2> elements. Even though we only output the title text for the <sect2> elements, we can still generate the appropriate multilevel numbers.

Test 5 generates numbers similarly to Test 4, except that it uses the from attribute. We generate numbers for <sect3> elements in four stages; first, we count the <chapter> ancestors, starting at the first <book> ancestor; then we count the <sect1> ancestors, starting at the first <chapter> ancestor, etc.

Test 6 starts counting at 1000 instead of 1. To do this, we have to store the value generated by <xsl:number> in a variable, then output the value of the variable plus 1000. Notice that we can use an expression in the value attribute of the <xsl:number> element. We also used the grouping-separator attribute to use a comma to separate groups of three digits.

Last but not least, Test 7 only numbers items from the first and second <sect1> elements (<sect1> elements whose position() is less than 3) in the second <chapter> element. Even though we're only processing these sections, we can still use <xsl:number> to generate the correct numbers for the elements.

<xsl:otherwise>Defines the else or default case in an <xsl:choose> element. This element always appears inside an <xsl:choose> element, and it must always appear last.

Category

Subinstruction (<xsl:otherwise> always appears as part of an <xsl:choose> element).

Required Attributes

None.

Optional Attributes

None.

Content

A template.

Appears in

The <xsl:choose> element.

Defined in

XSLT section 9.2, Conditional Processing with xsl:choose.

Example

As an example, we'll use an <xsl:choose> element that cycles through a set of values for the background color of a cell in an HTML table. We'll use this XML document as our input:

<?xml version="1.0"?>
<list xml:lang="en">
  <title>Albums I've bought recently:</title>
  <listitem>The Sacred Art of Dub</listitem>
  <listitem>Only the Poor Man Feel It</listitem>
  <listitem>Excitable Boy</listitem>
  <listitem xml:lang="sw">Aki Special</listitem>
  <listitem xml:lang="en-gb">Combat Rock</listitem>
  <listitem xml:lang="zu">Talking Timbuktu</listitem>
  <listitem xml:lang="jz">The Birth of the Cool</listitem>
</list>

Here is our stylesheet, which uses <xsl:choose> inside an <xsl:attribute> element to determine the correct value for the bgcolor attribute. We have an <xsl:otherwise> element that generates the value whitesmoke for every fourth <listitem> in our source document:

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

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>
          <xsl:value-of select="list/title"/>
        </title>
      </head>
      <body>
        <h1><xsl:value-of select="list/title"/></h1>
        <table border="1">
          <xsl:for-each select="list/listitem">
            <tr>
              <td>
                <xsl:attribute name="bgcolor">
                  <xsl:choose>
                    <xsl:when test="@bgcolor">
                      <xsl:value-of select="@bgcolor"/>
                    </xsl:when>
                    <xsl:when test="position() mod 4 = 0">
                      <xsl:text>papayawhip</xsl:text>
                    </xsl:when>
                    <xsl:when test="position() mod 4 = 1">
                      <xsl:text>mintcream</xsl:text>
                    </xsl:when>
                    <xsl:when test="position() mod 4 = 2">
                      <xsl:text>lavender</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:text>whitesmoke</xsl:text>
                    </xsl:otherwise>
                  </xsl:choose>
                </xsl:attribute>
                <xsl:value-of select="."/>
              </td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Here is our generated HTML document. Notice that every fourth row has a background color of whitesmoke; that value was generated by the <xsl:otherwise> element:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Albums I've bought recently:</title>
</head>
<body>
<h1>Albums I've bought recently:</h1>
<table border="1">
<tr>
<td bgcolor="mintcream">The Sacred Art of Dub</td>
</tr>
<tr>
<td bgcolor="lavender">Only the Poor Man Feel It</td>
</tr>
<tr>
<td bgcolor="whitesmoke">Excitable Boy</td>
</tr>
<tr>
<td bgcolor="papayawhip">Aki Special</td>
</tr>
<tr>
<td bgcolor="mintcream">Combat Rock</td>
</tr>
<tr>
<td bgcolor="lavender">Talking Timbuktu</td>
</tr>
<tr>
<td bgcolor="whitesmoke">The Birth of the Cool</td>
</tr>
</table>
</body>
</html>

When rendered, our HTML document looks like Figure A-7.

Figure A-7

Figure A-7. Document cycling among different background colors

<xsl:output>Defines the characteristics of the output document.

Category

Top-level element

Required Attributes

None.

Optional Attributes

method
Typically has one of three values: xml, html, or text. This value indicates the type of document that is generated. An XSLT processor can add other values to this list; how those values affect the generated document is determined by the XSLT processor.

version
Defines the value of the version attribute of the XML or HTML declaration in the output document. This attribute is used only when method="html" or method="xml".

encoding
Defines the value of the encoding attribute of the XML declaration in the output document.

omit-xml-declaration
Defines whether the XML declaration is omitted in the output document. Allowable values are yes and no. This attribute is used only when method="xml".

standalone
Defines the value of the standalone attribute of the XML declaration in the output document. Valid values are yes and no. This attribute is used only when method="xml".

doctype-public
Defines the value of the PUBLIC attribute of the DOCTYPE declaration in the output document. This attribute defines th