start page | rating of books | rating of authors | reviews | copyrights

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 the public identifier of the output document's DTD. It is used only when method="html" or method="xml".

doctype-system
Defines the value of the SYSTEM attribute of the DOCTYPE declaration in the output document. It defines the system identifier of the output document's DTD. This attribute is used only when method="html" or method="xml".

cdata-section-elements
Lists the elements that should be written as CDATA sections in the output document. All restrictions and escaping conventions of CDATA sections are handled by the XSLT processor. If you need to list more than one element, separate the element names with one or more whitespace characters. This attribute is used only when method="xml".

indent
Specifies whether the tags in the output document should be indented. Allowable values are yes and no. This attribute is used only when method="xml" or method="html", and the XSLT processor is not required to honor it.

media-type
Defines the MIME type of the output document.

Content

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

Appears in

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

Defined in

XSLT section 16, Output.

Example

To illustrate the three output methods defined in the XSLT specification, we'll create three stylesheets, each of which uses one of the three methods. We'll use the following XML document in all three examples:

<?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>

We'll now look at our three stylesheets and the results produced by each. First, let's look at the method="xml" stylesheet:

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

  <xsl:output 
    method="xml" 
    doctype-public="-//W3C/DTD XHTML 1.0//EN"
    doctype-system="file:///d:/xhtml.dtd"
    encoding="ISO-8859-1"
    indent="no"/>

  <xsl:template match="/">
    <html>
      <head>
        <title><xsl:value-of select="/list/title"/></title>
      </head>
      <body>
        <h1><xsl:value-of select="/list/title"/></h1>
        <p>
          <xsl:for-each select="/list/listitem">
            <xsl:number format="1. "/>
            <xsl:value-of select="."/>
            <br/>
          </xsl:for-each>
        </p>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

This stylesheet generates the following results:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C/DTD XHTML 1.0//EN" "file:///d:/xhtml.dtd"> 
<html><head><title>A few of my favorite albums</title> 
</head><body><h1>A few of my favorite albums</h1> 
<p>1. A Love Supreme<br/>2. Beat Crazy<br/>3. Here Come the  
Warm Jets<br/>4. Kind of Blue<br/>5. London Calling<br/>6. 
Remain in Light<br/>7. The Joshua Tree<br/>8. The Indestructible  
Beat of Soweto<br/></p></body></html>

(We actually added line breaks to this listing; the original output put everything from <html> through </html> on a single line.)

The output document has the encoding we specified in our stylesheet, and the DOCTYPE declaration includes the PUBLIC and SYSTEM identifiers we requested as well. Even with the line breaks we added, it's still obvious that this document has not been formatted with any extra whitespace whatsoever. We also have empty <br/> elements in our output document; those elements will be handled differently when we specify method="html". Speaking of which, here is our method="html" stylesheet:

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

  <xsl:output 
    method="html" 
    encoding="ISO-8859-1"
    doctype-public="-//W3C/DTD HTML 1.0 Transitional//EN"/>

  <xsl:template match="/">
    <html>
      <head>
        <title><xsl:value-of select="/list/title"/></title>
      </head>
      <body>
        <h1><xsl:value-of select="/list/title"/></h1>
        <p>
          <xsl:for-each select="/list/listitem">
            <xsl:number format="1. "/>
            <xsl:value-of select="."/>
            <br/>
          </xsl:for-each>
        </p>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Here is the HTML document generated by this stylesheet:

<!DOCTYPE HTML PUBLIC "-//W3C/DTD HTML 1.0 Transitional//EN">
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>A few of my favorite albums</title>
</head>
<body>
<h1>A few of my favorite albums</h1>
<p>1. A Love Supreme<br>2. Beat Crazy<br>3. Here Come 
the Warm Jets<br>4. Kind of Blue<br>5. London Calling<br>6. 
Remain in Light<br>7. The Joshua Tree<br>8. The Indestructible 
Beat of Soweto<br>
</p>
</body>
</html>

(As before, we added line breaks to make the listing legible.) Notice that the XSLT processor has automatically inserted a <META> element in the <head> of our HTML document. The <br> elements that were empty in our previous stylesheet are now old-fashioned <br> tags. Even though this style of XSLT output results in a document that is not valid XML (or XHTML), the document will work with existing HTML browsers.

Our final stylesheet will use method="text":

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

  <xsl:output method="text"/>

  <xsl:template match="/">
    <html>
      <head>
        <title><xsl:value-of select="/list/title"/></title>
      </head>
      <body>
        <h1><xsl:value-of select="/list/title"/></h1>
        <p>
          <xsl:for-each select="/list/listitem">
            <xsl:number format="1. "/>
            <xsl:value-of select="."/>
            <br/>
          </xsl:for-each>
        </p>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Here are the results, such as they are, from this stylesheet:

A few of my favorite albumsA few of my favorite albums1. A Love Supreme2. Beat 
Crazy3. Here Come the Warm Jets4. Kind of Blue5. London Calling6. Remain in 
Light7. The Joshua Tree8. The Indestructible Beat of Soweto

(As before, we inserted line breaks so the document would fit on the page.) These results are basically worthless. Why weren't our carefully coded HTML elements output to the text document? The reason is that the text output method only outputs text nodes to the result tree. Even though we requested that various HTML elements be generated along the way, they're ignored because we specified method="text".

<xsl:param>Defines the name and value of a parameter to be used by a template. This element can appear as a top-level element or inside the <xsl:template> element. If the <xsl:param> appears as a top-level element, it is a global parameter, visible to all areas of the stylesheet. The value of the parameter can be defined in one of two ways: specified in the select attribute, or defined in an XSLT template inside the <xsl:param> element itself.

Category

Instruction

Required Attributes

name
Defines the name of this parameter.

Optional Attributes

select
Contains an XPath expression that defines the value of this parameter.

Content

If the select attribute is used, <xsl:param> should be empty. Otherwise, it contains an XSLT template.

Appears in

<xsl:stylesheet> and <xsl:template>. If an <xsl:param> appears as a child of <xsl:stylesheet>, then it is a global parameter visible throughout the stylesheet. XSLT doesn't define the way global parameters are passed to the XSLT processor, so check the documentation for your processor to see how this is done. (See Section 4.4.3, "Global Parameters" in Chapter 4, "Branching and Control Elements" for an overview of how to pass parameters to the most popular XSLT processors.)

Defined in

XSLT section 11, Variables and Parameters.

Example

Here is a stylesheet that defines several <xsl:param> elements, both global and local. Notice that one of the parameters is a node-set; parameters can be of any XPath or XSLT datatype:

<?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:param name="favoriteNumber" select="23"/>
  <xsl:param name="favoriteColor"/>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="list/title"/>
    <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:with-param name="color" select="'yellow'"/>
      <xsl:with-param name="number" select="$favoriteNumber"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="processListitems">
    <xsl:param name="items"/>
    <xsl:param name="color" select="'blue'"/>

    <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:value-of select="$newline"/>
    
    <xsl:text>Your favorite color is </xsl:text>
    <xsl:value-of select="$favoriteColor"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>The color passed to this template is </xsl:text>
    <xsl:value-of select="$color"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

We'll use this stylesheet to transform 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>

Here are the results:


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

Your favorite color is purple.
The color passed to this template is yellow.

To generate these results, we passed the value purple to the XSLT processor. With Xalan, the value is passed like this:

java org.apache.xalan.xslt.Process -in test4.xml -xsl param.xsl 
  -param favoriteColor purple

(The command should be entered on a single line.) See Section 4.4.3, "Global Parameters" in Chapter 4, "Branching and Control Elements" for a more complete discussion of global parameters and how they can be set for various XSLT processors.

<xsl:preserve-space>Defines the source document elements for which whitespace should be preserved.

Category

Top-level element

Required Attributes

elements
This attribute defines the elements for which whitespace should be preserved. If you need to define more than one element, separate the element names with one or more whitespace characters.

Optional Attributes

None.

Content

None. <xsl:preserve-space> is an empty element.

Appears in

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

Defined in

XSLT section 3.4, Whitespace Stripping.

Example

We'll illustrate how <preserve-space> works 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:preserve-space elements="listing"/>

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

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="/code-sample/title"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/code-sample/listing">
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

We'll use this stylesheet to process the following document:

<?xml version="1.0"?>
<code-sample>
  <title>Conditional variable initialization</title>
  <listing>
  <type>int</type> <variable>y</variable> = <constant>23</constant>;
  <type>int</type> <variable>x</variable>;
    <keyword>if</keyword> (<variable>y</variable> > <constant>10</constant>)
    <variable>x</variable> = <constant>5</constant>;
  <keyword>else</keyword> 
    <keyword>if</keyword> (<variable>y</variable> > <constant>5</constant>)
      <variable>x</variable> = <constant>3</constant>;
  <keyword>else</keyword>
    <variable>x</variable> = <constant>1</constant>;
  </listing>
</code-sample>
      

When we process this document with our stylesheet, we get these results:


Conditional variable initialization

  int y = 23;
  int x;
    if (y > 10)
    x = 5;
  else
    if (y > 5)
      x = 3;
  else
    x = 1;

Compare this example to the one for the <strip-space> element.

<xsl:processing-instruction>Creates a processing instruction in the output document.

Category

Instruction

Required Attributes

name
Defines the name of this processing instruction.

Optional Attributes

None.

Content

An XSLT template. The contents of the template become the data of the processing instruction.

Appears in

<xsl:processing-instruction> appears inside a template.

Defined in

XSLT section 7.3, Creating Processing Instructions.

Example

We'll demonstrate a stylesheet that adds a processing instruction to an XML document. The processing instruction will associate the stylesheet template.xsl with this XML document. 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:processing-instruction name="xml-stylesheet">href="docbook/html/docbook.xsl" 
       type="text/xsl"</xsl:processing-instruction>
    <xsl:copy-of select="."/>
  </xsl:template>

</xsl:stylesheet>

This stylesheet simply uses the <xsl:copy-of> element to copy the input document to the result tree, adding a processing instruction along the way. We'll use 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:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="docbook/html/docbook.xsl" type="text/xsl"?>
<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>

Note that the contents of a processing instruction are text. Even though the processing instruction we just generated looks like it contains two attributes, you can't create the processing instruction like this:

<?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:processing-instruction name="xml-stylesheet">

      <!-- This doesn't work!  You can't put <xsl:attribute>
           elements inside a <xsl:processing-instruction> element. -->

      <xsl:attribute name="href">
        <xsl:text>docbook/html/docbook.xsl</xsl:text>
      </xsl:attribute>
      <xsl:attribute name="type">
        <xsl:text>text/xsl</xsl:text>
      </xsl:attribute>
    </xsl:processing-instruction>
    <xsl:copy-of select="."/>
  </xsl:template>

</xsl:stylesheet>

If you try this, you'll get an exception from the XSLT processor.

<xsl:sort>Defines a sort key for the current context. This element appears as a child of the <xsl:apply-templates> or <xsl:for-each> elements. Within those elements, the first <xsl:sort> defines the primary sort key, the second <xsl:sort> defines the secondary sort key, etc.

Category

Subinstruction (<xsl:sort> always appears as a child of the <xsl:apply-templates> or <xsl:for-each> elements)

Required Attributes

None.

Optional Attributes

select
An XPath expression that defines the nodes to be sorted.

lang
A string that defines the language used by the sort. The language codes are defined in RFC1766, available at http://www.ietf.org/rfc/rfc1766.txt.

data-type
An attribute that defines the type of the items to be sorted. Allowable values are number and text; the default is text. An XSLT processor has the option of supporting other values as well. Sorting the values 32 10 120 with data-type="text" returns 10 120 32, while data-type="number" returns 10 32 120.

order
An attribute that defines the order of the sort. Allowable values are ascending and descending.

case-order
An attribute that defines the order in which upper- and lowercase letters are sorted. Allowable values are upper-first and lower-first.

Content

None.

Appears in

<xsl:apply-templates> and <xsl:for-each>.

Defined in

XSLT section 10, Sorting.

Example

We'll illustrate <xsl:sort> with this 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:call-template name="ascending-alpha-sort">
      <xsl:with-param name="items" select="/sample/textlist/listitem"/>
    </xsl:call-template>
    <xsl:call-template name="ascending-alpha-sort">
      <xsl:with-param name="items" select="/sample/numericlist/listitem"/>
    </xsl:call-template>
    <xsl:call-template name="ascending-numeric-sort">
      <xsl:with-param name="items" select="/sample/numericlist/listitem"/>
    </xsl:call-template>
    <xsl:call-template name="descending-alpha-sort">
      <xsl:with-param name="items" select="/sample/textlist/listitem"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="ascending-alpha-sort">
    <xsl:param name="items"/>
    <xsl:text>Ascending text sort:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="$items">
      <xsl:sort select="."/>
      <xsl:value-of select="."/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template name="descending-alpha-sort">
    <xsl:param name="items"/>
    <xsl:text>Descending text sort:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="$items">
      <xsl:sort select="." order="descending"/>
      <xsl:value-of select="."/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template name="ascending-numeric-sort">
    <xsl:param name="items"/>
    <xsl:text>Ascending numeric sort:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="$items">
      <xsl:sort select="." data-type="number"/>
      <xsl:value-of select="."/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

Our stylesheet defines three named templates, each of which sorts <listitem>s in a different order or with a different data-type. We'll use this stylesheet against this document:

<?xml version="1.0"?>
<sample>
  <numericlist>
    <listitem>1</listitem>
    <listitem>3</listitem>
    <listitem>23</listitem>
    <listitem>120</listitem>
    <listitem>2</listitem>
  </numericlist>
  <textlist>
    <listitem>3</listitem>
    <listitem>apple</listitem>
    <listitem>orange</listitem>
    <listitem>dragonfruit</listitem>
    <listitem>carambola</listitem>
  </textlist>
</sample>

Here are the results:


Ascending text sort:
3
apple
carambola
dragonfruit
orange

Ascending text sort:
1
120
2
23
3

Ascending numeric sort:
1
2
3
23
120

Descending text sort:
orange
dragonfruit
carambola
apple
3

Notice that the data-type="numeric" attribute causes data to be sorted in numeric order.

<xsl:strip-space>Defines the source-document elements for which whitespace should be removed.

Category

Top-level element

Required Attributes

elements
Contains a space-separated list of source document elements for which nonsignificant whitespace should be removed. Nonsignificant whitespace typically means text nodes that contain nothing but whitespace; whitespace that appears in and around text is preserved.

Optional Attributes

None.

Content

None. <xsl:strip-space> is an empty element.

Appears in

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

Defined in

XSLT section 3.4, Whitespace Stripping.

Example

We'll illustrate the <xsl:strip-space> 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:strip-space elements="listing"/>

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

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="/code-sample/title"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/code-sample/listing">
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

We'll use this stylesheet to process the following document:

<?xml version="1.0"?>
<code-sample>
  <title>Conditional variable initialization</title>
  <listing>
  <type>int</type> <variable>y</variable> = <constant>23</constant>;
  <type>int</type> <variable>x</variable>;

    <keyword>if</keyword> (<variable>y</variable> > <constant>10</constant>)
    <variable>x</variable> = <constant>5</constant>;
  <keyword>else</keyword> 
    <keyword>if</keyword> (<variable>y</variable> > <constant>5</constant>)
      <variable>x</variable> = <constant>3</constant>;
  <keyword>else</keyword>
    <variable>x</variable> = <constant>1</constant>;
  </listing>
</code-sample>

Here are the results:


Conditional variable initialization
inty = 23;
  intx;
    if (y > 10)
    x = 5;
  elseif (y > 5)
      x = 3;
  elsex = 1;

Notice that all the extra whitespace from the <listing> element has been removed. This includes the space between the various elements contained inside <listing>, such as <keyword>, <constant>, and <variable>. Compare this example to the one for the <preserve-space> element.

<xsl:stylesheet>The root element of an XSLT stylesheet. It is identical to the <xsl:transform> element, which was included in the XSLT specification for historical purposes.

Category

Contains the entire stylesheet

Required Attributes

version
Indicates the version of XSLT that the stylesheet requires. For XSLT version 1.0, its value should always be "1.0". As later versions of the XSLT specification are defined, the required values for the version attribute will be defined along with them.

xmlns:xsl
Defines the URI for the XSL namespace. For XSLT Version 1.0, this attribute's value should be http://www.w3.org/1999/XSL/Transform. Note that most XSLT processors will give you a warning message if your xmlns:xsl declaration does not have the proper value.

Optional Attributes

id
Defines an ID for this stylesheet.

extension-element-prefixes

Defines any namespace prefixes used to invoke extension elements. Multiple namespace prefixes are separated by whitespace.

exclude-result-prefixes
Defines namespace prefixes that should not be sent to the output document. Multiple namespace prefixes are separated by whitespace.

Content

This element contains the entire stylesheet. The following items can be children of <xsl:stylesheet>:

Appears in

None. <xsl:stylesheet> is the root element of the stylesheet.

Defined in

XSLT section 2.2, Stylesheet Element.

Example

For the sake of completeness, we'll include an example here. We'll use the Hello World document from the XML 1.0 specification for our example:

<?xml version="1.0"?>
<greeting>
  Hello, World!
</greeting>

We'll transform our document with this stylesheet:

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

  <xsl:template match="/">
    <xsl:apply-templates select="greeting"/>
  </xsl:template>
  
  <xsl:template match="greeting">
    <html>
      <body>
        <h1>
          <xsl:value-of select="."/>
        </h1>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

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

<html>
<body>
<h1>
  Hello, World!
</h1>
</body>
</html>
<xsl:template>Defines an output template. For templates that begin <xsl:template match="x", the template defines a transformation for a given element. Templates that begin <xsl:template name="x" define a set of output elements that are processed whenever the template is invoked. All <xsl:template> elements must have either the match or the name attribute defined. Although not common, it is also possible to create <xsl:template> elements that have both a match and a name.

Category

Top-level element

Required Attributes

None.

Optional Attributes

match
A pattern that defines the elements for which this template should be invoked. For example, <xsl:template match="xyz"> defines a template for processing <xyz> elements.

name
An attribute that names this template. Named templates are invoked with the <xsl:call-template> element.

mode
An attribute that defines a mode for this template. A mode is a convenient syntax that allows you to 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.

priority
An attribute that assigns a numeric priority to this template. The value can be any numeric value except Infinity. If the XSLT processor cannot determine which template to use (in other words, more than one template has the same default priority), the priority attribute allows you to define a tiebreaker.

Content

An XSLT template.

Appears in

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

Defined in

XSLT section 5.3, Defining Template Rules.

Example

We'll use a template that copies all nodes from the input document to the output document, with one important difference: all attributes in the original document are converted to elements in the output document. The name of each generated element is the name of the original attribute, and the text of each element is the attribute's value. Here's 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: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>

Our stylesheet contains a single <xsl:template> that transforms every node in the original document. We'll use our stylesheet to transform 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 of our transformation:

<?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>
<xsl:text>Allows you to write literal text to the output document.

Category

Instruction

Required Attributes

None.

Optional Attributes

disable-output-escaping
Defines whether special characters are escaped when they are written to the output document. For example, if the literal text contains the character >, it is normally written to the output document as &gt;. If you code disable-output-escaping="yes", the character > is written instead. The XSLT processor uses this attribute only if you're using the html or xml output methods. If you're using <xsl:output method="text">, the attribute is ignored because output escaping is not done for the text output method.

Content

#PCDATA, literal text, and entity references.

Appears in

<xsl:text> appears inside a template.

Defined in

XSLT section 7.2, Creating Text.

Example

This sample stylesheet generates text with <xsl:text>. We intermingle <xsl:text> elements and <xsl:value-of> elements to create a coherent sentence. In this case, we simply generate a text document, but this technique works equally well to create the text of an HTML or XML element. Here is 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:text>Your document contains </xsl:text>
    <xsl:value-of select="count(//*)"/>
    <xsl:text> elements and </xsl:text>
    <xsl:value-of select="count(//@*)"/>
    <xsl:text> attributes. </xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text disable-output-escaping="yes"><Have a great day!></xsl:text>
  </xsl:template>
</xsl:stylesheet>

Also notice our use of <xsl:variable> to generate line breaks. The <xsl:text> element inside the <xsl:variable> element contains a line break, so writing the value of that variable to the result tree gives us the line break we want. Given this 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>

Our stylesheet produces these results:

Your document contains 9 elements and 5 attributes.
<Have a great day!>

Since we use the text output method, the disable-output-escaping attribute has no effect. If you change the stylesheet to use <xsl:output method="html"/> or <xsl:output method="xml"/>, then disable-output-escaping is used. Here are the results for disable-output-escaping="yes":

Your document contains 10 elements and 2 attributes.
<Have a great day!>

And here are the results for disable-output-escaping="no", the default:

Your document contains 10 elements and 2 attributes.
&lt;Have a great day!&gt;
<xsl:transform>This is a synonym for <xsl:stylesheet>. It was included in the XSLT 1.0 spec for historical purposes. Its attributes, content, and all other properties are the same as those for <xsl:stylesheet>. See <xsl:stylesheet> for more information.

<xsl:value-of>Calculates the value of an XPath expression, converts that value to a string, and then writes the value to the result tree.

Category

Instruction

Required Attributes

select
The XPath expression that is evaluated and written to the output document.

Optional Attributes

disable-output-escaping
An attribute that defines whether special characters are escaped when written to the output document. For example, if the literal text contains the character >, it is normally written to the output document as &gt;. If you code disable-output-escaping="yes", the character > is written instead. The XSLT processor uses this attribute only if you use the html or xml output methods. If you use <xsl:output method="test">, the attribute is ignored becasue output escaping is not done for the text output method. See Reference A.30 for a more thorough discussion of the disable-output-escaping attribute.

Content

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

Appears in

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

Defined in

XSLT section 7.6.1, Generating Text with xsl:value-of.

Example

We'll use the <xsl:value-of> element to generate some text. Here is our stylesheet:

<?xsl 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:text>Your document contains</xsl:text>
    <xsl:value-of select="count(//*)"/>
    <xsl:text> elements and </xsl:text>
    <xsl:value-of select="count(//@*)"/>
    <xsl:text> attributes.  </xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>Have a great day!</xsl:text>
  </xsl:template>
</xsl:stylesheet>

We'll use this XML document as input:

<?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:

Your document contains 14 elements and 4 attributes.
Have a great day!
<xsl:variable>Defines a variable. If <xsl:variable> occurs as a top-level element, it is a global variable that is accessible throughout the stylesheet. Otherwise, the variable is local and exists only in the element that contains the <xsl:variable>. The value of the variable can be defined in one of two ways: specified in the select attribute or defined in an XSLT template inside the <xsl:variable> element itself. If neither method is used, the value of the variable is an empty string.

Category

Either a top-level element or an instruction

Required Attributes

name
An attribute that names this variable.

Optional Attributes

select
An XPath expression that defines the value of this variable.

Content

The <xsl:variable> element can be empty, or it can contain an XSLT template. If it contains an XSLT template, the value of the select attribute (if any exists) is ignored.

Appears in

<xsl:stylesheet> as a top-level element or in a template.

Defined in

XSLT section 11, Variables and Parameters.

Example

Here is a stylesheet that defines a number of variables:

<?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="favoriteNumber" select="23"/>
  <xsl:variable name="favoriteColor" select="'blue'"/>
  <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:text>Hello!  Your favorite number is </xsl:text>
    <xsl:value-of select="$favoriteNumber"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>Your favorite color is </xsl:text>
    <xsl:value-of select="$favoriteColor"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="$newline"/>
    <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:variable name="favoriteColor">
      <xsl:text>chartreuse</xsl:text>
    </xsl:variable>
    
    <xsl:text>    (Your favorite color is now </xsl:text>
    <xsl:value-of select="$favoriteColor"/>
    <xsl:text>.)</xsl:text>
    <xsl:value-of select="$newline"/>
    <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>

We'll use our stylesheet to transform the following 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>

Here are the results of our transformation:

Hello!  Your favorite number is 23.
Your favorite color is blue.

Here is a moderately long list:
    (Your favorite color is now chartreuse.)
1.  The Sacred Art of Dub
2.  Only the Poor Man Feel It
3.  Excitable Boy
4.  Aki Special
5.  Combat Rock
6.  Talking Timbuktu
7.  The Birth of the Cool

Several things are worth mentioning in our stylesheet. First, notice that when we defined values for the first two variables (favoriteNumber and favoriteColor), we had to quote the string "blue", but didn't have to quote 23. If we don't quote blue, the XSLT processor assumes we mean all the <blue> elements in the current context. We don't have to quote 23 because XML element names can't start with a number. It's a good idea to always quote literals, even those that can't be element names; chances are good that you'll forget this process at some point.

Also notice that we have two variables named favoriteColor. One is a global variable because its parent is the <xsl:stylesheet> element; the other is a local variable because it is defined in a <xsl:template>. When we access favoriteColor in the match="/" template, it has one value; when we access it inside the name="processListitems" template, it has another. Having two variables at the same level with the same name is an error. It's also an error to define an <xsl:variable> and an <xsl:param> with the same name at the same level.

Using an <xsl:choose> element to initialize an <xsl:variable> is a common technique. This technique is the equivalent of this procedural programming construct:

String complicatedVariable;
if (count(listitems) > 10)
  complicatedVariable = "really long list";
else if (count(listitems)) > 5)
  complicatedVariable = "moderately long list";
else
  complicatedVariable = "fairly short list";

The last point we'll make is that a variable can be any of the XPath or XSLT variable types, including a node-set. When we call the processListitems template, the parameter we pass to it is a variable containing the node-set of all the <listitem> elements in our document. Inside the processListitems template, our variable (which is now technically a parameter) can be used inside an <xsl:for-each> element.

<xsl:when>Defines one branch of an <xsl:choose> element. It is equivalent to the Java case statement.

Category

Subinstruction (<xsl:when> always appears as a child of an <xsl:choose> element)

Required Attributes

test
Contains a boolean expression that is evaluated. If the expression evaluates to true, the contents of the <xsl:when> element are processed; otherwise, the contents of the <xsl:when> are ignored.

Optional Attributes

None.

Content

An XSLT template.

Appears in

The <xsl:choose> element only.

Defined in

XSLT section 9.2, Conditional Processing with xsl:choose.

Example

This example uses an <xsl:choose> element and three <xsl:when> elements to cycle through a set of values. Now we will generate rows of an HTML table for each <listitem>:

<?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>

In our stylesheet, we'll generate table rows with the background colors of mintcream, lavender, whitesmoke, and papayawhip. For each <listitem> in our source document, one of the <xsl:when> elements (or the <xsl:otherwise> element) generates the appropriate color.

<?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>
      

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

<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>

All <td> elements with a background color of papayawhip, mintcream, or lavender were generated by one of the <xsl:when> elements.

<xsl:with-param>Defines a parameter to be passed to a template. When the template is invoked, values can be passed in for the parameter.

Category

Subinstruction (<xsl:with-param> always appears inside an <xsl:apply-templates> or <xsl:call-template> element)

Description

<xsl:with-param> defines a parameter to be passed to a template. When the template is invoked, values can be passed in for the parameter. The value of the parameter can be defined in one of three ways:

If no value is passed to the template (<xsl:with-param name="x"/>), then the default value of the parameter, if any, is used instead. The default value of the parameter is defined on the <xsl:param> element inside the <xsl:template> itself; see the description of the <xsl:param> element for more details.

Required Attributes

name
Names this parameter.

Optional Attributes

select
An XPath expression that defines the value of this parameter.

Content

The <xsl:with-param> element can be empty, or it can contain an XSLT template. If it contains an XSLT template, the value of the select attribute (if any exists) is ignored.

Appears in

<xsl:apply-templates> and <xsl:call-template>.

Defined in

XSLT section 11.6, Passing Parameters to Templates.

Example

Here is a stylesheet with a number of parameters. Notice that some parameters are global and defined outside 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:param name="favoriteNumber" select="23"/>
  <xsl:param name="favoriteColor"/>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="list/title"/>
    <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:with-param name="color" select="'yellow'"/>
      <xsl:with-param name="number" select="$favoriteNumber"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="processListitems">
    <xsl:param name="items"/>
    <xsl:param name="color" select="'blue'"/>

    <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:value-of select="$newline"/>
    
    <xsl:text>Your favorite color is </xsl:text>
    <xsl:value-of select="$favoriteColor"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>The color passed to this template is </xsl:text>
    <xsl:value-of select="$color"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

We'll use this stylesheet to transform 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>

Our stylesheet contains two global parameters, favoriteNumber and favoriteColor, and defines a default value for favoriteNumber. The stylesheet also passes a parameter from the match="/" template to the name="processListitems" template; that parameter contains a node-set. Here are the results of the transformation:


Albums I've bought recently:
1.  The Sacred Art of Dub
2.  Only the Poor Man Feel It
3.  Excitable Boy
4.  Aki Special
5.  Combat Rock
6.  Talking Timbuktu
7.  The Birth of the Cool

Your favorite color is orange.
The color passed to this template is yellow.

To generate these results with Xalan, we use this command:

java org.apache.xalan.xslt.Process -in test4.xml -xsl with-param.xsl 
  -param favoriteColor orange

The command should appear on a single line. See Section 4.4.3, "Global Parameters" in Chapter 4, "Branching and Control Elements" for a complete discussion of global parameters and how you define them for various XSLT processors.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.