eXtensible Stylesheet Language Transformations

XSLT is a declarative programming language for transforming XML or any other text. It searches for parts of an XML document that match a series of predefined templates, and then applies transformation and formatting rules to each matched part. Another language, XPath, is used to help in finding those matching parts.

How XSLT Works

An XSLT stylesheet is used to define the transformation rules to be applied on the target XML document. XSLT stylesheet is written in XML format. XSLT Processor takes the XSLT stylesheet and applies the transformation rules on the target XML document and then it generates a formatted document in the form of XML, HTML, or text format. Possibly, this formatted document is then utilized by XSLT formatter to generate the actual output which is to be displayed to the end-user.

Gentle Introduction to XML through an Example

Here is the contents of an XML file named greeting.xml:

<?xml version="1.0"?>
<?xml-stylesheet href="greeting.xsl" type="text/xsl"?>
<greeting>
  Hello, World!
</greeting>

to be transformed into html format by stylesheet greeting.xsl. The second line asks the browser to process the contents. If you omit it, you can feed greeting.xml and greeting.xsl to an XSLT processor such as xsltproc, as found in linux. The contents of the stylesheet are:

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

The root element is <xsl:stylesheet> , or the synonym <xsl:transform>. You must always specify the XSLT namespace, and it is important to set the version attribute correctly to match the type of processing required. After you've declared the namespace, all the XSLT element names require the namespace prefix, which is xsl: by convention. The prefix also makes it clear which element is referenced if other namespaces are in use. The version attribute on the <xsl:stylesheet> element is rather confusing. It has absolutely nothing to do with the version of XSLT; rather, it refers to the version of XML to be output.

In XSLT 1.0, the method attribute can take the values "xml", "html" , or "text". The XSLT 2.0 specification adds "xhtml" to the possible attribute values.

You can add in the output tag two more attributes specifying the XHTML doctype-system and doctype-public attribute values. These will result in the processor generating correct declarations in the output, before the html element:

<xsl:output
  method="xml"
  encoding="UTF-8"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
  doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/>

You are not restricted to following the nested nodes as shown in this example. You might want to select all the paragraphs in the source document for processing, in which case you would use <xsl:apply-templates select= "//p"/>.

The XSLT Namespace

All standard XSLT elements are in the http://www.w3.org/1999/XSL/Transform namespace. In this section, we assume that this URI is mapped to the xsl prefix using an appropriate xmlns:xsl declaration somewhere in the stylesheet. This mapping is normally declared on the root element like this:

<xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <!-- XSLT top-level elements go here -->
    </xsl:stylesheet>

Embedding Stylesheets in XML Documents

XSLT stylesheets are often used in a batch environment as separate files, but it is also possible to embed a stylesheet directly in an XML document, possibly to deliver the document directly to a browser for rendering. This means that the XML document must be aware of the stylesheet.

There is a separate recommendation from the W3C that identifies the process for embedding stylesheets in XML documents, called Associating Style Sheets with XML Documents, Version 1.0. This recommendation describes a predefined XML processing instruction, or PI, that can be used at the top of any XML document to allow the XML to find the top of the XSLT stylesheet, wherever it is in the XML.

The PI uses an href attribute with a URI to point to the ID of the <xsl:stylesheet> element. This URI must be a fragment identifier (signalled by the # prefix) because it is a reference to a part of the document containing the PI. It is not used to reference an external stylesheet. The following PI model definition shows the two required attributes and four optional attributes for the <?xml-stylesheet?> PI:

<?xml-stylesheet
  href= string
  type= string
  title = string
  media = string
  charset = string
  alternate = "yes" | "no"
?>

The following example, taken directly from the XSLT specification, shows an embedded stylesheet in an XML document. Notice that this example contains a few elements from the XSL formatting objects specification. The stylesheet is called into play with the <?xml-stylesheet?> PI. The template rule matching on id('foo') in the example finds an element in the XML with an ID of "foo" and uses the instructions in the template to format it, in this case with a bold font.

<?xml-stylesheet type="text/xml" href="#style1"?>
<!DOCTYPE doc SYSTEM "doc.dtd">
<doc>
  <head>
    <xsl:stylesheet id="style1"
               version="1.0"
             xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <xsl:import href="doc.xsl"/>
      <xsl:template match="id('foo')">
        <fo:block font-weight="bold"><xsl:apply-templates/></fo:block>
      </xsl:template>
      <xsl:template match="xsl:stylesheet">
        <!-- ignore -->
      </xsl:template>
    </xsl:stylesheet>
    </head>
  <body>
    <para id="foo">
    ...
    </para>
  </body>
</doc>

The template rule matching on xsl:stylesheet is required in all embedded stylesheets so that <xsl:stylesheet> elements are processed as elements.

Linking to a Stylesheet

Client−side transformation

Client−side transformation is supported by XSLT processors embedded in browsers. Client−side transformation has the advantage that you can spread the processing overhead onto the client machines. However, it means you are dependent on the client browser dealing correctly with the XSLT.

The following XML file sets its own stylesheet for the browser to process:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="class.xsl"?>

<class>
  <student>Jack</student>
  <student>Harry</student>
  <student>Rebecca</student>
  <teacher>Mr. Bean</teacher>
</class>

The stylesheet (named class.xsl) in turn should produce XHTML code:

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

	<xsl:template match="teacher">
		<p><u><xsl:value-of select="."/></u></p>
	</xsl:template>

	<xsl:template match="student">
		<p><b><xsl:value-of select="."/></b></p>
	</xsl:template>
	<xsl:template match="/">
		<html>
		<body>
		<xsl:apply-templates/>
		</body>
		</html>
	</xsl:template>

</xsl:stylesheet>

The XML file class.xml is linked to the XSLT code by adding the xml-stylesheet reference. The XSLT code then applies its rules to transform the XML document.

Value Types

There are four value types in XPath, and two that are introduced by XSLT. The four basic value types are as follows:

XSLT introduces two further value types:

Nodes

When an application wants to operate on an XML document (such as an XSLT processor running an XSLT stylesheet over an XML document), it builds an internal model of what the document looks like. In general, this model is known as a document object model or DOM. In XPath and XSLT, it's called a node tree. Nodes are the abstract components that make up a node tree. Many different kinds of nodes exist, and each type represents a different kind of component in an XML document. The following node types are significant in XSLT:

The node tree reflects the logical form of the document rather than its physical form, which means that node trees don't contain nodes representing things such as the XML declaration, the DOCTYPE declaration, CDATA sections, or entities within the document. The top node of any node tree is the root node. The top−most element in a document is called the document element. In a well−formed XML document, only one document element ever exists. The nodes that appear within a node in a node tree are known as its children. As you might expect, then, every node except for the very top node has a parent. In most instances, a node' parent is an element node, with the only exception to this being nodes that are directly under the root node (the document element and any top−level processing instructions or comments).

XSLT Elements V 1.0 (w3schools)

This section is drawn from the pages in www.w3schools.com. For coverage of latest features, aka XSLT 2.0, see Appendix.

These are:

XSLT apply-imports
Applies a template rule from an imported style sheet
XSLT apply-templates
Applies a template rule to the current element or to the current element's child nodes
XSLT attribute
Adds an attribute
XSLT attribute-set
Defines a named set of attributes
XSLT call-template
Calls a named template
XSLT choose
Used in conjunction with <when> and <otherwise> to express multiple conditional tests
XSLT comment
Creates a comment node in the result tree
XSLT copy
Creates a copy of the current node (without child nodes and attributes)
XSLT copy-of
Creates a copy of the current node (with child nodes and attributes)
XSLT decimal-format
Defines the characters and symbols to be used when converting numbers into strings, with the format-number() function
XSLT element
Creates an element node in the output document
XSLT fallback
Specifies an alternate code to run if the processor does not support an XSLT element
XSLT for-each
Loops through each node in a specified node set
XSLT if
Contains a template that will be applied only if a specified condition is true
XSLT import
Imports the contents of one style sheet into another. Note: An imported style sheet has lower precedence than the importing style sheet
XSLT include
Includes the contents of one style sheet into another. Note: An included style sheet has the same precedence as the including style sheet
XSLT key
Declares a named key that can be used in the style sheet with the key() function
XSLT message
Writes a message to the output (used to report errors)
XSLT namespace-alias
Replaces a namespace in the style sheet to a different namespace in the output
XSLT number
Determines the integer position of the current node and formats a number
XSLT otherwise
Specifies a default action for the <choose> element
XSLT output
Defines the format of the output document
XSLT param
Declares a local or global parameter
XSLT preserve-space
Defines the elements for which white space should be preserved
XSLT processing-instruction
Writes a processing instruction to the output
XSLT sort
Sorts the output
XSLT strip-space
Defines the elements for which white space should be removed
XSLT stylesheet and transform
Defines the root element of a style sheet
XSLT template
Rules to apply when a specified node is matched
XSLT text
Writes literal text to the output
XSLT value-of
Extracts the value of a selected node
XSLT variable
Declares a local or global variable
XSLT when
Specifies an action for the <choose> element
XSLT with-param
Defines the value of a parameter to be passed into a template

xsl:apply-imports

Definition and Usage

The xsl:apply-imports element applies a template rule from an imported style sheet.

Template rules in imported style sheets have lower precedence than template rules in main style sheets. The xsl:apply-imports is used when we want to use a template rule from the imported style sheet rather than an equivalent rule in the main style sheet.

Example

Suppose we have a style sheet called standard.xsl that contains a template rule for message elements:

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

<xsl:template match="message">
  <h2><xsl:apply-templates/></h2>
</xsl:template>

</xsl:stylesheet>

Another style sheet could import standard.xsl, and modify the message elements, like this:

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

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

<xsl:template match="message">
  <div style="border:solid blue">
  <xsl:apply-imports/>
  </div>
</xsl:template>

</xsl:stylesheet> 

The result would be to transform a message into an element of the form:

<div style="border:solid blue"><h2>...</h2></div>

xsl:apply-templates

Definition and Usage

The xsl:apply-templates element applies a template to the current element or to the current element's child nodes.

If we add a select attribute to the xsl:apply-templates element it will process only the child element that matches the value of the attribute. We can use the select attribute to specify in which order the child nodes are to be processed.

Syntax

<xsl:apply-templates select="expression" mode="name">

  <!-- Content:(xsl:sort|xsl:with-param)* -->

</xsl:apply-templates>

Attributes

select <expression> (optional)
Specifies the nodes to be processed. An asterisk selects the entire node-set. If this attribute is omitted, all child nodes of the current node will be selected
mode <name> (optional)
If there are multiple ways of processing defined for the same element, distinguishes among them

Example 1

Wrap a single h1 element around each title element in the document:

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

<xsl:template match="title">
  <h1><xsl:apply-templates/></h1>
</xsl:template>

</xsl:stylesheet> 

Example 2

Wrap a single h1 element around all the title elements which are children of message:

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

<xsl:template match="message">
  <h1><xsl:apply-templates select="title"/></h1>
</xsl:template>

</xsl:stylesheet>

Example 3

Wrap a single h1 element around all the child nodes of message that have the mode attribute set to big:

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

<xsl:template match="message">
  <h1><xsl:apply-templates select="*" mode="big"/></h1>
</xsl:template>

</xsl:stylesheet> 

xsl:attribute

Definition and Usage

The xsl:attribute> element is used to add attributes to elements.

Syntax

<xsl:attribute name="attributename" namespace="uri">

  <!-- Content:template -->

</xsl:attribute>

Attributes

name <attributename> (required)
Specifies the name of the attribute
namespace <URI> (Optional)
Defines the namespace URI for the attribute

Example 1

Add a source attribute to the picture element:

<picture>
  <xsl:attribute name="source"/>
</picture> 

Example 2

Add a source attribute to the picture element and fill it with values from images/name :

<picture>
  <xsl:attribute name="source">
    <xsl:value-of select="images/name" />
  </xsl:attribute>
</picture> 

Example 3

Create an attribute-set that can be applied to any output element:

<xsl:attribute-set name="font">
  <xsl:attribute name="fname">Arial</xsl:attribute>
  <xsl:attribute name="size">14px</xsl:attribute>
  <xsl:attribute name="color">red</xsl:attribute>
</xsl:attribute-set> 

xsl:attribute-set

Definition and Usage

The xsl:attribute-set element creates a named set of attributes. The attribute-set can be applied as whole to the output document.

Syntax

<xsl:attribute-set
name="name" use-attribute-sets="name-list">

  <!-- Content:xsl:attribute* -->

</xsl:attribute-set>

Attributes

name <name> (required)
Specifies the name of the attribute-set
use-attribute-sets <name-list> (optional)
A white space separated list of other attribute-sets to use in the attribute-set

Example

Create an attribute-set that can be applied to any output element:

<xsl:attribute-set name="font">
  <xsl:attribute name="fname">Arial</xsl:attribute>
  <xsl:attribute name="size">14px</xsl:attribute>
  <xsl:attribute name="color">red</xsl:attribute>
</xsl:attribute-set> 

xsl:call-template

Definition and Usage

The xsl:call-template element calls a named template.

Syntax

<xsl:call-template name="templatename">

  <!-- Content:xsl:with-param* -->

</xsl:call-template>

Attributes

name <templatename> (required)
Specifies the name of the template to be called

Example

Call a template named "description" when the processor finds a car element:

<xsl:template match="car">
  <xsl:call-template name="description"/>
</xsl:template> 

xsl:choose

Definition and Usage

The xsl:choose element is used in conjunction with xsl:when and xsl:otherwise to express multiple conditional tests.

If no xsl:when is true, the content of xsl:otherwise is processed.

If no xsl:when is true, and no xsl:otherwise element is present, nothing is created.

For simple conditional testing, use the xsl:if element instead.

Syntax

<xsl:choose>

  <!-- Content:(xsl:when+,xsl:otherwise?) -->

</xsl:choose>

Example 1

The code below will add a pink background-color to the artist column WHEN the price of the CD is higher than 10.

<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <tr>
        <td><xsl:value-of select="title"/></td>
        <xsl:choose>
          <xsl:when test="price &gt; 10">
            <td bgcolor="#ff00ff">
            <xsl:value-of select="artist"/></td>
          </xsl:when>
          <xsl:otherwise>
            <td><xsl:value-of select="artist"/></td>
          </xsl:otherwise>
        </xsl:choose>
      </tr>
      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

Example 2

Declare a variable named color. Set its value to the color attribute of the current element. If the current element has no color attribute, the value of color will be green:

<xsl:variable name="color">
  <xsl:choose>
    <xsl:when test="@color">
      <xsl:value-of select="@color"/>
    </xsl:when>
    <xsl:otherwise>green</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

xsl:comment

Definition and Usage

The xsl:comment element is used to create a comment node in the result tree.

Syntax

<xsl:comment>

  <!-- Content:template -->

</xsl:comment>

Example

<xsl:comment>This is a comment!</xsl:comment>

xsl:copy

Definition and Usage

The xsl:copy element creates a copy of the current node.

Syntax

<xsl:copy use-attribute-sets="name-list">

  <!-- Content:template -->

</xsl:copy>

Attributes

use-attribute-sets <name-list> (optional)
A white space separated list of attribute-sets to apply to the output node, if the node is an element

Example

Copy the message node to the output document:

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

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

</xsl:stylesheet> 

xsl:copy-of

Definition and Usage

The xsl:copy-of element creates a copy of the current node.

This element can be used to insert multiple copies of the same node into different places in the output.

Syntax

<xsl:copy-of select="expression"/>

Attributes

select <expression> (required)
Specifies what to be copied

Example

The following code...

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

<xsl:variable name="header">
  <tr>
  <th>Element</th>
  <th>Description</th>
  </tr>
</xsl:variable>

<xsl:template match="/">
  <html>
  <body>
  <table>
    <xsl:copy-of select="$header" />
    <xsl:for-each select="reference/record">
    <tr>
    <xsl:if test="category='XML'">
      <td><xsl:value-of select="element"/></td>
      <td><xsl:value-of select="description"/></td>
    </xsl:if>
    </tr>
    </xsl:for-each>
  </table>
  <br />
  <table>
    <xsl:copy-of select="$header" />
    <xsl:for-each select="table/record">
    <tr>
    <xsl:if test="category='XSL'">
      <td><xsl:value-of select="element"/></td>
      <td><xsl:value-of select="description"/></td>
    </xsl:if>
    </tr>
    </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:decimal-format

Definition and Usage

The xsl:decimal-format element defines the characters and symbols to be used when converting numbers into strings, with the format-number() function.

Not all countries use the same characters for separating the decimal part from the integer part, and for grouping digits. With the xsl:decimal-format element you can change special characters to other symbols.

This element is a top level element.

The format-number() function can refer to the xsl:decimal-format element by name.

Syntax

<xsl:decimal-format
  name="name"
  decimal-separator="char"
  grouping-separator="char"
  infinity="string"
  minus-sign="char"
  NaN="string"
  percent="char"
  per-mille="char"
  zero-digit="char"
  digit="char"
  pattern-separator="char"/>

Attributes

name <name> (optional)
Specifies a name for this format
decimal-separator <char> (optional)
Specifies the decimal point character. Default is "."
grouping-separator <char> (optional)
Specifies the thousands separator character. Default is ","
infinity <string> (optional)
Specifies the string used to represent infinity. Default is "Infinity"
minus-sign <char> (optional)
Specifies the character to represent negative numbers. Default is "-"
NaN <string> (optional)
Specifies the string used when the value is not a number". Default is "NaN"
percent <char> (optional)
Specifies the percentage sign character. Default is "%"
per-mille <char> (optional)
Specifies the per thousand sign character. Default is "‰"
zero-digit <char> (optional)
Specifies the digit zero character. Default is "0"
digit <char> (optional)
Specifies the character used to indicate a place where a digit is required. Default is #
pattern-separator <char> (optional)
Specifies the character used to separate positive and negative subpatterns in a format pattern. Default is ";"

Example

The example below shows how to format to European currency (note that the third argument in format-number() refers to the name of the xsl:decimal-format element:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:decimal-format name="euro" decimal-separator="," grouping-separator="."/>
  <xsl:template match="/">
    <xsl:value-of select="format-number(26825.8, '#.###,00', 'euro')"/>
  </xsl:template>
</xsl:stylesheet>

Output:

26.825,80

xsl:element

Definition and Usage

The xsl:element element is used to create an element node in the output document.

Syntax

<xsl:element
name="name"
namespace="URI"
use-attribute-sets="namelist">

  <!-- Content:template -->

</xsl:element>

Attributes

name <name> (required)
Specifies the name of the element to be created (the value of the name attribute can be set to an expression that is computed at run-time, like this: xsl:element name="{$country}"/
namespace <URI> (optional)
Specifies the namespace URI of the element (the value of the namespace attribute can be set to an expression that is computed at run-time, like this: xsl:element name="{$country}" namespace="{$someuri}"/
use-attribute-sets <namelist> (optional)
A white space separated list of attribute-sets containing attributes to be added to the element

Example

Create a "singer" element that contains the value of each artist element:

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

<xsl:template match="/">
  <xsl:for-each select="catalog/cd">
    <xsl:element name="singer">
      <xsl:value-of select="artist" />
    </xsl:element>
    <br />
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

xsl:fallback

Definition and Usage

The xsl:fallback element specifies an alternate code to run if the XSL processor does not support an XSL element.

Syntax

<xsl:fallback>

  <!-- Content: template -->

</xsl:fallback>

Example

This example is supposed to loop through each "title" element with a made up xsl:loop element. If the XSL processor does not support this element (which it does not), it will use the xsl:for-each element instead:

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

<xsl:template match="catalog/cd">
  <xsl:loop select="title">
    <xsl:fallback>
      <xsl:for-each select="title">
        <xsl:value-of select="."/>
      </xsl:for-each>
    </xsl:fallback>
  </xsl:loop>
</xsl:template>

</xsl:stylesheet>

xsl:for-each

Definition and Usage

The xsl:for-each element loops through each node in a specified node set.

Syntax

<xsl:for-each select="expression">
  <!-- Content -->
</xsl:for-each>

Attributes

select <expression> (required)
An XPath expression that specifies which node set to be processed.

Example 1

The example below loops trough each cd element outputs the title for each cd:

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

<xsl:template match="/">
  <div>
    <xsl:for-each select="catalog/cd">
      <p><xsl:value-of select="title" /></p>
    </xsl:for-each>
  </div>
</xsl:template>

</xsl:stylesheet>

Example 2

The example below loops trough each cd element and creates a table row with the values from title and artist for each cd:

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

<xsl:template match="/">
  <html>
  <body>
    <h1>Music Collection:</h1>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <tr>
        <td><xsl:value-of select="title" /></td>
        <td><xsl:value-of select="artist" /></td>
      </tr>
      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

xsl:if

Definition and Usage

The xsl:if element contains a template that will be applied only if a specified condition is true.

Use xsl:choose in conjunction with xsl:when and xsl:otherwise to express multiple conditional tests!

Syntax

<xsl:if
test="expression">

  <!-- Content: template -->

</xsl:if>

Attributes

test <expression> (required)
Specifies the condition to be tested

Example 1

Select the values of title and artist IF the price of the CD is higher than 10:

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

<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <xsl:if test="price &gt; 10">
        <tr>
          <td><xsl:value-of select="title"/></td>
          <td><xsl:value-of select="artist"/></td>
        </tr>
      </xsl:if>
      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

Example 2

Display the title of each CD. Insert ", " between each CD-title if it is not the last CD or the last but one. If it is the last CD, add "!" behind the title. If it is the last but one CD, add ", and " behind the title:

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

<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <p>Titles:
    <xsl:for-each select="catalog/cd">
      <xsl:value-of select="title"/>
      <xsl:if test="position()!=last()">
        <xsl:text>, </xsl:text>
      </xsl:if>
      <xsl:if test="position()=last()-1">
        <xsl:text> and </xsl:text>
      </xsl:if>
      <xsl:if test="position()=last()">
        <xsl:text>!</xsl:text>
      </xsl:if>
    </xsl:for-each>
    </p>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:import

Definition and Usage

The xsl:import element is a top-level element that is used to import the contents of one style sheet into another.

Syntax

<xsl:import href="URI"/>

Attributes

href <URI> (required)
Specifies the URI of the style sheet to import

Example

Suppose you have a style sheet called cdcatalog_ex3.xsl:

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

<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <tr>
        <td><xsl:value-of select="catalog/cd/title"/></td>
        <td><xsl:value-of select="catalog/cd/artist"/></td>
      </tr>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

A second style sheet called cdcatalog_import.xsl imports cdcatalog_ex3.xsl:

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

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

<xsl:template match="/">
  <xsl:apply-imports/>
</xsl:template>

</xsl:stylesheet> 

xsl:include

Definition and Usage

The xsl:include element is a top-level element that includes the contents of one style sheet into another.

Syntax

<xsl:include href="URI"/>

Attributes

href <URI> (required)
Specifies the URI of the style sheet to import

Example


          

xsl:key

Definition and Usage

The xsl:key element is a top-level element which declares a named key that can be used in the style sheet with the key() function.

Syntax

<xsl:key
name="name"
match="pattern"
use="expression"/>

Attributes

name <name> (required)
Specifies the name of the key
match <pattern> (required)
Defines the nodes to which the key will be applied
use <expression> (required)
The value of the key for each of the nodes

Example

Suppose you have an XML file called persons.xml:

<persons>
  <person name="Tarzan" id="050676"/>
  <person name="Donald" id="070754"/>
  <person name="Dolly" id="231256"/>
</persons>

You can define a key in an XSL file like this:

<xsl:key name="preg" match="person" use="@id"/>

To find the person with id="050676", write (in the XSL file):

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

<xsl:key name="preg" match="person" use="@id"/>

<xsl:template match="/">
  <html>
  <body>
  <xsl:for-each select="key('preg','050676')">
    <p>
    Id: <xsl:value-of select="@id"/><br />
    Name: <xsl:value-of select="@name"/>
    </p>
  </xsl:for-each>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:message

Definition and Usage

The xsl:message element writes a message to the output. This element is primarily used to report errors.

This element can contain almost any other XSL element (xsl:text, xsl:value-of, etc.).

The terminate attribute gives you the choice to either quit or continue the processing when an error occurs.

Syntax

<xsl:message terminate="yes|no">

  <!-- Content:template -->

</xsl:message>

Attributes

terminate yes/no (optiona)
"yes" terminates the processing after the message is written to the output. "no" continues the processing after the message is written to the output. Default is "no".

Example

Check if artist is an empty string. If yes, we quit the XSL processor and display a message:

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

<xsl:template match="/">
  <html>
  <body>
  <xsl:for-each select="catalog/cd">
    <p>Title: <xsl:value-of select="title"/><br />
    Artist:
    <xsl:if test="artist=''">
      <xsl:message terminate="yes">
        Error: Artist is an empty string!
      </xsl:message>
    </xsl:if>
    <xsl:value-of select="artist"/>
    </p>
  </xsl:for-each>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:namespace-alias

Definition and Usage

The xsl:namespace-alias element is used to replace a namespace in the style sheet to a different namespace in the output.

Syntax

<xsl:namespace-alias
                stylesheet-prefix="prefix|#default"
                result-prefix="prefix|#default"/>

Attributes

stylesheet-prefix prefix/#default (required)
Specifies the namespace you wish to change
result-prefix prefix#default (required)
Specifies the desired namespace for the output

Example

The wxsl prefix is converted to the xsl prefix in the output:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wxsl="https://www.w3schools.com/w3style.xsl">

<xsl:namespace-alias stylesheet-prefix="wxsl" result-prefix="xsl"/>

<xsl:template match="/">
  <wxsl:stylesheet>
    <xsl:apply-templates/>
  </wxsl:stylesheet>
</xsl:template>

</xsl:stylesheet>

xsl:number

Definition and Usage

The xsl:number element is used to determine the integer position of the current node in the source. It is also used to format a number.

<xsl:number
count="expression"
level="single|multiple|any"
from="expression"
value="expression"
format="formatstring"
lang="languagecode"
letter-value="alphabetic|traditional"
grouping-separator="character"
grouping-size="number"/>

Syntax


          

Attributes

count <expression> (optional)
An XPath expression that specifies what nodes are to be counted
level single/multiple/any (optional)
Controls how the sequence number is assigned. Can be one of the following: single (default) multiple, any (not supported by Netscape 6)
from <expression> (optional)
An XPath expression that specifies where the counting will start
value <expression> (optional)
Specifies a user-provided number that is used in place of a sequence generated number
format formatstring (optional)

Defines the output format for the number. Can be one of the following:

  • format="1" results in 1 2 3 . .
  • format="01" results in 01 02 03 (not supported by Netscape 6)
  • format="a" results in a b c . . (not supported by Netscape 6)
  • format="A" results in A B C. . (not supported by Netscape 6)
  • format="i" results in i ii iii iv . . (not supported by Netscape 6)
  • format="I" results in I II III IV . . (not supported by Netscape 6)
lang languagecode (optional)
Specifies the language alphabet to be used for the numbering (Not supported by Netscape 6)
letter-value alphabetic/traditional (optional)
Specifies whether the numbering in the selected language is alphabetic or traditional. The default is alphabetic
grouping-separator character (optional)
Specifies what character should be used to separate groups of digits. The default is the comma
grouping-size number (optional)
Specifies how many digits are in the groups that are being separated by the character specified in the grouping-separator attribute. The default is 3

Example 1

<xsl:number value="250000" grouping-separator="."/>

Output:

250.000

Example 2

<xsl:number value="250000" grouping-size="2"/>

Output:

25,00,00

Example 3

<xsl:number value="12" grouping-size="1"
                grouping-separator="#" format="I"/>

Output:

X#I#I

Example 4

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

<xsl:template match="/">
  <html>
  <body>
  <p>
  <xsl:for-each select="catalog/cd">
    <xsl:number value="position()" format="1" />
    <xsl:value-of select="title" /><br />
  </xsl:for-each>
  </p>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:otherwise

Definition and Usage

The xsl:otherwise element specifies a default action for the xsl:choose element. This action will take place when none of the xsl:when conditions apply.

Syntax

<xsl:otherwise>

  <!-- Content:template -->

</xsl:otherwise>

Example 1

The code below will add a pink background-color to the artist column WHEN the price of the cd is higher than 10, OTHERWISE it will just print the name of the artist:

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

<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <tr>
        <td><xsl:value-of select="title"/></td>
        <xsl:choose>
          <xsl:when test="price&gt;'10'">
            <td bgcolor="#ff00ff">
            <xsl:value-of select="artist"/></td>
          </xsl:when>
          <xsl:otherwise>
            <td><xsl:value-of select="artist"/></td>
          </xsl:otherwise>
        </xsl:choose>
      </tr>
      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

Example 2

Declare a variable named color. Set its value to the color attribute of the current element. If the current element has no color attribute, the value of color will be green:

<xsl:variable name="color">
  <xsl:choose>
    <xsl:when test="@color">
      <xsl:value-of select="@color"/>
    </xsl:when>
    <xsl:otherwise>green</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

xsl:output

Definition and Usage

The xsl:output element defines the format of the output document.

Syntax

<xsl:output
method="xml|html|text|name"
version="string"
encoding="string"
omit-xml-declaration="yes|no"
standalone="yes|no"
doctype-public="string"
doctype-system="string"
cdata-section-elements="namelist"
indent="yes|no"
media-type="string"/>

Attributes

method xml/html/text/name (optional)
Defines the output format. The default is XML (but if the first child of the root node is html and there are no preceding text nodes, then the default is HTML) Netscape 6 only supports "html" and "xml"
version string (optional)
Sets the W3C version number for the output format (only used with method="html" or method="xml")
encoding <string> (optional)
Sets the value of the encoding attribute in the output
omit-xml-declaration yes/no (optional)
"yes" specifies that the XML declaration (<?xml...?>) should be omitted in the output. "no" specifies that the XML declaration should be included in the output. The default is "no"
standalone yes/no (optional)
"yes" specifies that a standalone declaration should occur in the output. "no" specifies that a standalone declaration should not occur in the output. The default is "no" (This attribute is not supported by Netscape 6)
doctype-public <string> (optional)
Sets the value of the PUBLIC attribute of the DOCTYPE declaration in the output
doctype-system <string> (optional)
Sets the value of the SYSTEM attribute of the DOCTYPE declaration in the output
cdata-section-elements <namelist> (optional)
A white-space separated list of elements whose text contents should be written as CDATA sections
indent yes/no (optional)
"yes" indicates that the output should be indented according to its hierarchic structure. "no" indicates that the output should not be indented according to its hierarchic structure. This attribute is not supported by Netscape 6
media-type <string> (optional)
Defines the MIME type of the output. The default is "text/xml" This attribute is not supported by Netscape 6

Example 1

The output in this example will be an XML document, version 1.0. The character encoding is set to "UTF-8" and the output will be indented for readability:

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

<xsl:output method="xml" version="1.0"
encoding="UTF-8" indent="yes"/>

...

...

</xsl:stylesheet>

Example 2

The output in this example will be an HTML document, version 4.0. The character encoding is set to "UTF-8" and the output will be indented for readability:

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

<xsl:output method="html" version="4.0"
encoding="UTF-8" indent="yes"/>

...

...

</xsl:stylesheet>

xsl:param

Definition and Usage

The xsl:param element is used to declare a local or global parameter.

Syntax

<xsl:param
name="name"
select="expression">

  <!-- Content:template -->

</xsl:param>

Attributes

name <name> (required)
Specifies the name of the parameter
select <expression> (optional)
Specifies an XPath expression that specifies a default value for the parameter

Example

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

<xsl:template match="/">
  <html>
  <body>
  <xsl:for-each select="catalog/cd">
    <xsl:call-template name="show_title">
      <xsl:with-param name="title" select = "title" />
    </xsl:call-template>
  </xsl:for-each>
  </body>
  </html>
</xsl:template>

<xsl:template name = "show_title" >
  <xsl:param name = "title" />
  <p>Title: <xsl:value-of select = "$title" /></p>
</xsl:template>

</xsl:stylesheet>

xsl:processing-instruction

Definition and Usage

The xsl:processing-instruction element writes a processing instruction to the output.

Syntax

<xsl:processing-instruction
name="process-name">

  <!-- Content:template -->

</xsl:processing-instruction>

Attributes

name <process-name> (required)
Specifies the name of the processing instruction

Example

This code:

<xsl:processing-instruction name="xml-stylesheet">
href="style.css" type="text/css"
</xsl:processing-instruction>

Creates this tag:

<?xml-stylesheet href="style.css" type="text/css"?>

xsl:sort

Definition and Usage

The xsl:sort element is used to sort the output.

Syntax

<xsl:sort select="expression"
lang="language-code"
data-type="text|number|qname"
order="ascending|descending"
case-order="upper-first|lower-first"/>

Attributes

select <XPath-expression> (optional)
Specifies which node/node-set to sort on
lang <language-code> (optional)
Specifies which language is to be used by the sort
data-type "text/number/qname" (optional)
Specifies the data-type of the data to be sorted. Default is "text
order "ascending/descending" (optional)
Specifies the sort order. Default is "ascending"
case-order "upper-first/lower-first" (optional)
Specifies whether upper- or lowercase letters are to be ordered first

Example

The example below will sort the output by artist:

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

<xsl:template match="/">
  <html>
  <body>
  <h2>My CD Collection</h2>
  <table border="1">
    <tr bgcolor="#9acd32">
      <th>Title</th>
      <th>Artist</th>
    </tr>
    <xsl:for-each select="catalog/cd">
      <xsl:sort select="artist"/>
      <tr>
        <td><xsl:value-of select="title"/></td>
        <td><xsl:value-of select="artist"/></td>
      </tr>
    </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:stylesheet and xsl transform Elements

Definition and Usage

The xsl:stylesheet and xsl:transform elements are completely synonymous elements. Both are used to define the root element of the style sheet.

Syntax

<xsl:stylesheet
id="name"
version="version"
extension-element-prefixes="list"
exclude-result-prefixes="list">

  <!-- Content:(<xsl:import>*,top-level-elements) -->

</xsl:stylesheet>

<xsl:transform
id="name"
version="version"
extension-element-prefixes="list"
exclude-result-prefixes="list">

  <!-- Content:(<xsl:import>*,top-level-elements) -->

</xsl:transform>

Attributes

version <version> (required)
Specifies the XSLT version of the style sheet
extension-element-prefixes <list> (optional)
A white space separated list of namespace prefixes used for extension elements. This attribute is not supported by Netscape 6
exclude-result-prefixes <list> (optional)
A white space separated list of namespace prefixes that should not be sent to the output
id <name> (optional)
A unique id for the style sheet. This attribute is not supported by Netscape 6

Example 1

<?xml version="1.0" encoding="UTF-8"?>

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

....

....

</xsl:stylesheet>

Example 2

<?xml version="1.0" encoding="UTF-8"?>

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

....

....

</xsl:transform>

xsl:template

Definition and Usage

The xsl:template> element contains rules to apply when a specified node is matched. The match attribute is used to associate the template with an XML element. The match attribute can also be used to define a template for a whole branch of the XML document (i.e. match="/" defines the whole document).

Syntax

<xsl:template
name="name"
match="pattern"
mode="mode"
priority="number">

  <!-- Content:(<xsl:param>*,template) -->

</xsl:template>

Attributes

name <name> (optional)

Specifies a name for the template.

match <pattern> (optional)

The match pattern for the template.

mode <mode> (optional)
Specifies a mode for this template
priority <number> (optional)
A number which indicates the numeric priority of the template

Example

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

<xsl:template match="/">
  <html>
  <body>
  <h2>My CD Collection</h2>
  <xsl:apply-templates/>
  </body>
  </html>
</xsl:template>

<xsl:template match="cd">
  <p>
  <xsl:apply-templates select="title"/>
  <xsl:apply-templates select="artist"/>
  </p>
</xsl:template>

<xsl:template match="title">
  Title: <span style="color:#ff0000">
  <xsl:value-of select="."/></span>
  <br />
</xsl:template>

<xsl:template match="artist">
  Artist: <span style="color:#00ff00">
  <xsl:value-of select="."/></span>
  <br />
</xsl:template>

</xsl:stylesheet>

xsl:text

Definition and Usage

The xsl:text element is used to write literal text to the output.

Syntax

<xsl:text
disable-output-escaping="yes|no">

  <!-- Content:#PCDATA -->

</xsl:text>

Attributes

disable-output-escaping yes/no (optional)
"yes" indicates that special characters (like "<") should be output as is. "no" indicates that special characters (like "<") should be output as "&lt;". Default is "no". This attribute is not supported by Netscape 6

Example

Displays the title of each CD. Inserts a ", " between each cd-title if it is not the last CD - or the last but one. If it is the last CD, it will add a "!" behind the title. If it is the last but one, add a ", and " behind the title:

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

<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <p>Titles:
    <xsl:for-each select="catalog/cd">
      <xsl:value-of select="title"/>
      <xsl:if test="position() < last()-1">
        <xsl:text>, </xsl:text>
      </xsl:if>
      <xsl:if test="position()=last()-1">
        <xsl:text>, and </xsl:text>
      </xsl:if>
      <xsl:if test="position()=last()">
        <xsl:text>!</xsl:text>
      </xsl:if>
    </xsl:for-each>
    </p>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:preserve-space

Definition and Usage

The xsl:preserve-space element is used to define the elements for which white space should be preserved.

Syntax

<xsl:preserve-space elements="list-of-element-names"/>
<xsl:strip-space elements="list-of-element-names"/>

Attributes

elements

Required. A white space separated list of element names for which white space should be preserved/removed.

Example

In the example below we preserve white space nodes for title and artist elements, and remove white space nodes for country, company, price, and year elements:

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

<xsl:strip-space elements="country company price year" />
<xsl:preserve-space elements="title artist" />

<xsl:template match="/">
  <html>
  <body>
  <xsl:for-each select="catalog/cd">
    <p>
    <xsl:value-of select="title" /><br />
    <xsl:value-of select="artist" /><br />
    <xsl:value-of select="country" /><br />
    <xsl:value-of select="company" /><br />
    <xsl:value-of select="price" /><br />
    <xsl:value-of select="year" />
    </p>
  </xsl:for-each>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:strip-space

Definition and Usage

The xsl:strip-space element is used to define the elements for which white space should be removed.

Syntax

<xsl:preserve-space elements="list-of-element-names"/>
<xsl:strip-space elements="list-of-element-names"/>

Attributes

elements <list-of-element-names> (required)

A white space separated list of element names for which white space should be preserved/removed.

Example

In the example below we preserve white space nodes for title and artist elements, and remove white space nodes for country, company, price, and year elements:

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

                <xsl:strip-space elements="country company price year" />
                <xsl:preserve-space elements="title artist" />

                <xsl:template match="/">
                  <html>
                  <body>
                  <xsl:for-each select="catalog/cd">
                    <p>
                      <xsl:value-of select="title" /><br />
                      <xsl:value-of select="artist" /><br />
                      <xsl:value-of select="country" /><br />
                      <xsl:value-of select="company" /><br />
                      <xsl:value-of select="price" /><br />
                      <xsl:value-of select="year" />
                    </p>
                  </xsl:for-each>
                </body>
              </html>
            </xsl:template>

            </xsl:stylesheet>

xsl:value-of

Definition and Usage

The xsl:value-of element extracts the value of a selected node. The xsl:value-of element can be used to select the value of an XML element and add it to the output.

Syntax

<xsl:value-of select="expression" disable-output-escaping="yes|no" />

Attributes

select <expression> (required)
An XPath expression that specifies which node/attribute to extract the value from. It works like navigating a file system where a forward slash (/) selects subdirectories.
disable-output-escaping yes/no (optional)
"yes" indicates that special characters (like "<") should be output as is. "no" indicates that special characters (like "<") should be output as "&lt;". Default is "no".

Example 1

The example below puts the values from the first title and artist elements and puts it in a table:

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

<xsl:template match="/">
  <html>
  <body>
    <h1>Music Collection:</h1>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <tr>
        <td><xsl:value-of select="catalog/cd/title" /></td>
        <td><xsl:value-of select="catalog/cd/artist" /></td>
      </tr>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

Example 2

The example below loops trough each cd element and creates a table row with the values from title and artist for each cd element:

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

<xsl:template match="/">
  <html>
  <body>
    <h1>Music Collection:</h1>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <tr>
        <td><xsl:value-of select="title" /></td>
        <td><xsl:value-of select="artist" /></td>
      </tr>
      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:variable

Definition and Usage

The xsl:variable element is used to declare a local or global variable.

You can add a value to a variable by the content of the xsl:variable element OR by the select attribute!

Syntax

<xsl:variable
name="name"
select="expression">

  <!-- Content:template -->

</xsl:variable>

Attributes

name <name> (required)
Specifies the name of the variable
select <expression> (optional)
Defines the value of the variable

Example 1

If the select attribute is present, the xsl:variable element cannot contain any content. If the select attribute contains a literal string, the string must be within quotes. The following two examples assign the value "red" to the variable "color":

<xsl:variable name="color" select="'red'" />

<xsl:variable name="color" select='"red"' />

Example 2

If the xsl:variable element only contains a name attribute, and there is no content, then the value of the variable is an empty string:

<xsl:variable name="j" />

Example 3

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

<xsl:variable name="header">
  <tr bgcolor="#9acd32">
    <th>Title</th>
    <th>Artist</th>
  </tr>
</xsl:variable>

<xsl:template match="/">
  <html>
  <body>
  <table border="1">
    <xsl:copy-of select="$header" />
    <xsl:for-each select="catalog/cd">
      <tr>
        <td><xsl:value-of select="title"/></td>
        <td><xsl:value-of select="artist"/></td>
      </tr>
    </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

xsl:when

Definition and Usage

The xsl:when element is used to specify an action for the xsl:choose element. The xsl:when element evaluates an expression, and if it returns true, an action is performed.

Syntax

<xsl:when
test="boolean-expression">

  <!-- Content: template -->

</xsl:when>

Attributes

test <boolean-expression> (required)
Specifies a Boolean expression to be tested

Example 1

The code below will add a pink background-color to the artist column WHEN the price of the cd is higher than 10.

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

<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <tr>
        <td><xsl:value-of select="title"/></td>
        <xsl:choose>
          <xsl:when test="price&gt;'10'">
            <td bgcolor="#ff00ff">
            <xsl:value-of select="artist"/></td>
          </xsl:when>
          <xsl:otherwise>
            <td><xsl:value-of select="artist"/></td>
          </xsl:otherwise>
        </xsl:choose>
      </tr>
      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

Example 2

Declare a variable named "color". Set its value to the color attribute of the current element. If the current element has no color attribute, the value of "color" will be "green":

<xsl:variable name="color">
  <xsl:choose>
    <xsl:when test="@color">
      <xsl:value-of select="@color"/>
    </xsl:when>
    <xsl:otherwise>green</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

xsl:with-param

Definition and Usage

The xsl:with-param element defines the value of a parameter to be passed into a template.

You can add a value to the parameter by the content of the xsl:with-param element OR by the select attribute!

Syntax

<xsl:with-param
name="name"
select="expression">

  <!-- Content:template -->

</xsl:with-param>

Attributes

name <name> (required)
Specifies the name of the parameter
select <expression> (optional)
An XPath expression that defines the value of the parameter

Example

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

<xsl:template match="/">
  <html>
  <body>
  <xsl:for-each select="catalog/cd">
    <xsl:call-template name="show_title">
      <xsl:with-param name="title" select = "title" />
    </xsl:call-template>
  </xsl:for-each>
  </body>
  </html>
</xsl:template>

<xsl:template name = "show_title" >
  <xsl:param name = "title" />
  <p>Title: <xsl:value-of select = "$title" /></p>
</xsl:template>

</xsl:stylesheet>

Templates

An XSLT stylesheet is comprised of a number of templates that define a particular part of the process. Templates are defined with xsl:template elements, each of which holds a sequence of XSLT instructions that are carried out when the template is used. The two ways of using templates are by calling them and by applying them. If an xsl:template element has a name attribute, it defines a named template, and you can use it by calling it with xsl:call–template. If an xsl:template element has a match attribute, it defines a matching template, and you can apply it by applying templates to a node that it matches using xsl:apply–templates.

The syntax of the xsl:template element is:

<xsl:template
   name = Qname
   match = Pattern
   priority = number
   mode = QName >
>>

where the meaning of the attributes are:

name
Name of the element on which template is to be applied. This allows calling (running) the template by name
match
Pattern which signifies the element(s) on which template is to be applied.
priority
Priority number of a template. Matching template with low priority is not considered in from in front of high priority template.
mode
Allows element to be processed multiple times to produce a different result each time.

Built−in templates

Several built−in templates are designed to assist you by providing default processing for different kinds of nodes. These templates have the following effects:

  • The content of the root node is processed.
  • Elements are ignored, but their contents are processed.
  • Any text in the source is copied to the result.
  • All other nodes are ignored.

When the processor starts processing the stylesheet, it begins by taking the root node of the source node tree and trying to find a template to apply to it. If you create an XSLT stylesheet without any templates in it, the processor processes the content of the root node, which includes the document element. Then, it processes the content of the document element, which may include other elements, and so on, recursively down the node tree. When it encounters a text node, it outputs that text node. The effect of this is that if you have a stylesheet that doesn't contain any templates then you will get all the text in the source XML as output.

These are the built-in templates:

Built-in template rule for element and document nodes

This template processes the document node and any of its children. This processing ensures that recursive processing will continue, even if no template is declared for a given element:

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

Built-in template rule for modes

This template ensures that element and document nodes are processed, regardless of any mode that might be in effect.

<xsl:template match="*|/" mode="x">
  <xsl:apply-templates mode="x"/>
</xsl:template>

Built-in template rule for text and attribute nodes

This template copies the text of all text and attribute nodes to the output tree. Be aware that you have to actually select the text and attribute nodes for this rule to be invoked:

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

Built-in template rule for comment and processing instruction nodes

This template does nothing:

<xsl:template match="comment()|processing-instruction()"/>

Built-in template rule for namespace nodes

This template also does nothing:

<xsl:template match="namespace()"/>

Copying and Transforming

In general you can start with a default copy template:

<xsl:template match="node() | @*">
  <xsl:copy>
    <xsl:apply-templates select="node() | @*"/>
  </xsl:copy>
</xsl:template>

or

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"/>
<!-- Copy all elements, attributes, and text nodes -->
<xsl:template match="*|@*|text()|comment()">
  <xsl:copy>
    <xsl:apply-templates select="*|@*|text()|comment()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

and then add your specific processing rules, which might either erase some nodes, or rename or restructure some nodes, or something else.

<value-of select="...">

<copy select="...">

<copy-of select="...">

The xsl:copy-of element creates a copy of the current node. Namespace nodes, child nodes, and attributes of the current node are automatically copied as well! This element can be used to insert multiple copies of the same node into different places in the output. Its select is required and specifies what to be copied

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

<xsl:variable name="header">
  <tr>
  <th>Element</th>
  <th>Description</th>
  </tr>
</xsl:variable>

<xsl:template match="/">
  <html>
  <body>
  <table>
    <xsl:copy-of select="$header" />
    <xsl:for-each select="reference/record">
    <tr>
    <xsl:if test="category='XML'">
      <td><xsl:value-of select="element"/></td>
      <td><xsl:value-of select="description"/></td>
    </xsl:if>
    </tr>
    </xsl:for-each>
  </table>
  <br />
  <table>
    <xsl:copy-of select="$header" />
    <xsl:for-each select="table/record">
    <tr>
    <xsl:if test="category='XSL'">
      <td><xsl:value-of select="element"/></td>
      <td><xsl:value-of select="description"/></td>
    </xsl:if>
    </tr>
    </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet> 

xsl:copy vs. xsl:copy-of

The xsl:copy instruction copies the context item but none of its children nodes. It cannot have a @select XPath. A very common use of xsl:copy can be found in the identity transformation:

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

Notice that here the node itself is copied via xsl:copy and the children nodes are then transformed via xsl:apply-templates, giving other templates a chance to intervene in the transformation.

The xsl:copy-of instruction evaluates the XPath in its required @select attribute and copies the selected nodes and their children nodes, recursively. This is a deep copy. The xsl:copy-of instruction must have a @select XPath. Notice that xsl:copy-of could have been used in the identity transformation, however the flexibility afforded by allowing other templates the chance to match during the recursion would have been lost.

  • Use xsl:copy when you want to copy just the context item and have other plans for the children of the context item.
  • Use xsl:copy-of when you want to copy XPath-selected nodes and their children, recursively.

In short, xsl:copy makes a shallow copy, whereas xsl:copy-of makes a deep copy.

Named Templates

These have a name attribute, so that they may be called by call-template with matching name parameter.

The mode Attribute

Sometimes the same input content needs to appear multiple times in the output document, formatted according to a different template each time. For instance, the titles of the chapters in a book would be formatted one way in the chapters themselves and a different way in the table of contents. Both xsl:apply-templates and xsl:template elements can have optional mode attributes that connect different template rules to different uses. A mode attribute on xsl:template element identifies in which mode that template rule should be activated. An xsl:apply-templates element with a mode attribute only activates template rules with matching mode attributes.

The example below demonstrates with a stylesheet that begins the output document with a list of people's names. This is accomplished in the toc mode. Then a separate template rule, as well as a separate xsl:apply-templates element in the default mode (really no mode at all), output the complete contents of all person elements.

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

  <xsl:template match="people">
    <html>
      <head><title>Famous Scientists</title></head>
      <body>
        <ul><xsl:apply-templates select="person" mode="toc"/></ul>
        <xsl:apply-templates select="person"/>
      </body>
    </html>
  </xsl:template>

  <!-- Table of Contents Mode Templates -->
  <xsl:template match="person" mode="toc">
    <xsl:apply-templates select="name" mode="toc"/>
  </xsl:template>

  <xsl:template match="name" mode="toc">
    <li><xsl:value-of select="last_name"/>,
    <xsl:value-of select="first_name"/></li>
  </xsl:template>

  <!-- Normal Mode Templates -->
  <xsl:template match="person">
    <p><xsl:apply-templates/></p>
  </xsl:template>

</xsl:stylesheet>

Both xsl:template and xsl:apply-templates have an optional mode attribute. If xsl:template does not have a match attribute, it must not have a mode attribute. If an xsl:apply-templates element has a mode attribute, then it applies only to those template rules from xsl:template elements that have a mode attribute with the same value; if an xsl:apply-templates element does not have a mode attribute, then it applies only to those template rules from xsl:template elements that do not have a mode attribute.

Template priority

When a processor is told to apply templates to a node set, it goes through the nodes one by one and tries to find a matching template that matches each node. When it finds one, it uses that template to process the node. There might be more than one template that matches the node. Templates with a higher import priority override templates that are imported.

If multiple templates remain after discounting ones that have been imported, then the processor assigns a priority to each template. The priority of a template can be set explicitly with the priority attribute on xsl:template. Otherwise, the priority is based on the pattern in the match attribute, from lowest to highest as follows:

  • Patterns that match all nodes of a particular type (e.g. all elements)
  • Patterns that match nodes in a particular namespace (e.g. all XHTML elements)
  • Patterns that match nodes by name (e.g. all p elements)
  • Patterns that include additional tests through predicates or through additional steps (e.g. all p elements that are descendents of a table element)

If more than one template matches a node, and they have the same priority, the processor uses the last template defined in the stylesheet.

Top-Level Elements

Any element whose parent is the xsl:stylesheet element is called a top-level element. Here we're simply setting up some properties for the transform. There are other elements we can put at the start of our stylesheet. Here is a brief discussion of these:

xsl:include and xsl:import

These elements refer to another stylesheet. The other stylesheet and all of its contents are included in the current stylesheet. The main difference between xsl:import and xsl:include is that a template, variable, or anything else imported with xsl:import has a lower priority than the things in the current stylesheet. This gives you a mechanism to subclass stylesheets, if you want to think about this from an object-oriented point of view. You can import another stylesheet that contains common templates, but any templates in the importing stylesheet will be used instead of any templates in the imported stylesheet. Another difference is that xsl:import can only appear at the beginning of a stylesheet, while xsl:include can appear anywhere.

xsl:strip-space and xsl:preserve-space

These elements contain a space-separated list of elements from which whitespace should be removed or preserved in the output. To define these elements globally, use xsl:strip-space elements="*"/ or xsl:preserve-space elements="*"/ . If we want to specify that whitespace be removed for all elements except for greeting elements and salutation elements, we would add this markup to our stylesheet:

xsl:key

This element defines a key, which is similar to defining an index on a database.

xsl:variable

This element defines a variable. Any xsl:variable that appears as a top-level element is global to the entire stylesheet.

xsl:param

This element defines a parameter. As with xsl:variable , any xsl:param that is a top-level element is global to the entire stylesheet.

How to Avoid Exporting Namespace Definitions to Resulting XML Documents

I'd like to take data from some XML files and transform them into a new XML document. However, I do not want the definition of a namespace in the XSLT to occur in the result document.

You can use the exclude-result-prefixes attribute of the xsl:stylesheet element to avoid emitting namespace prefixes into the output document:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns:prefix1="http://www.something.com"
         exclude-result-prefixes="prefix1">

</xsl:stylesheet>

To suppress multiple namespaces from the output document specify them separated by whitespace:

exclude-result-prefixes="prefix1 prefix2 prefix3"

From the XSLT specification:

When a stylesheet uses a namespace declaration only for the purposes of addressing the source tree, specifying the prefix in the exclude-result-prefixes attribute will avoid superfluous namespace declarations in the result tree.

Use extension-element-prefixes

Use extension-element-prefixes="Namespace" like:

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:datetime="http://exslt.org/dates-and-times"
xmlns:str="http://exslt.org/strings"
xmlns:exsl="http://exslt.org/common"
xmlns:uw="xalan://ru.sbtc.util.XSLUtil"
extension-element-prefixes="exsl str datetime uw"
version="1.0">

extension-element-prefixes does have the same effect, but it has an additional effect. Any elements that you put in one of those namespaces will be interpreted as an extension element (rather than a literal result element). That may well be appropriate for the examples you have in your answer. But if you don't want that additional behavior, then just use exclude-result-prefixes

Push and Pull Processing

In push processing a template rule is provided (written) for each kind of node. Then templates are applied for children of each node, and so on. Built-in templates are applied whenever a matching one has not been provided.

Push processing is used when input and output have the same structure.

In pull processing you explicitly select and process the required nodes.

Push Processing

...

Here is an example of turning a docbook file into HTML:

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

  <xsl:template match="book">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <title><xsl:value-of select="book/title"/></title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="para">
    <p><xsl:apply-templates/></p>
  </xsl:template>

  <xsl:template match="title">
    <h1><xsl:apply-templates/></h1>
  </xsl:template>

</xsl:stylesheet>

Each xsl:apply-templates instruction is the stylesheet's way of telling the XSLT processor to send along the context node's child nodes to the stylesheet's relevant template rules. (Or, to quote Curtis Mayfield, "Keep On Pushing.")

Pull Processing

In pull processing you explicitly select and process the required nodes. To this end the following elements are used:

  • <xsl:value-of select='pattern'/>
  • <xsl:apply-templates select='pattern'/>
  • <xsl:for-each select='pattern'/>

Pull processing affords greater control over which nodes are to be processed. It is employed whenever input and output have very different structure.

A pull stylesheet is appropriate when you are fairly certain of what your source document will look like. It's also a good idea if the structure of the result drives the processing; i.e., if you just want to pick certain information out of the source document and place it in the result.

A Simple Example

Here is an simple example.

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

  <xsl:template match="/">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <title><xsl:value-of select="book/title"/></title>
      </head>
      <body>
        <h1><xsl:value-of select="book/title"/></h1>
        <xsl:for-each select="book/para">
          <p><xsl:value-of select="."/></p>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

...

A Full Example

Here elements are selected (1) by name or (2) by attribute, and (3) other elements are outsourced through the document(FILE_NAME) function.

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

  <xsl:template match="/">

    <xsl:element name="book">
      <xsl:element name="title">Pulling Elements either by Name or by Attribute Value</xsl:element>

      <xsl:text>
      </xsl:text>


      <!-- Pull all preface elements -->
      <xsl:apply-templates select="document('../book.xml')/book//preface"/><xsl:text>

      </xsl:text>
      <!-- Pull all elements with a class attribute whose value is 'private' -->
      <xsl:apply-templates select="/book//*[@class='private']"/>

    </xsl:element>


  </xsl:template>

  <!-- Copy all elements, attributes, and text nodes -->
<xsl:template match="*|@*|text()|comment()">
  <xsl:copy>
    <xsl:apply-templates select="*|@*|text()|comment()"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>


Pulling and Sorting

You want to call an empty sort element <xsl:sort select="NODE-SET"/> inside a <xsl:for-each select="ELEMENT">...</xsl:for-each> element.

In the follwing example only the titles of chapters are pulled, and then sorted:

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

  <xsl:template match="/">

    <xsl:element name="book">
      <xsl:element name="title">Pulling Chapter <tag>title</tag> Elements and sorting by <userinput>./title</userinput></xsl:element><xsl:text>
</xsl:text>

      <xsl:for-each select='//chapter'>
        <xsl:sort select="./title | ./info/title"/>
        <xsl:apply-templates select="title | info/title"/><xsl:text>
</xsl:text>
      </xsl:for-each>

    </xsl:element>


  </xsl:template>

  <!-- Copy all elements, attributes, and text nodes -->
<xsl:template match="*|@*|text()|comment()">
  <xsl:copy>
    <xsl:apply-templates select="*|@*|text()|comment()"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>
Other Ordering Attributes

We may change the sorting criterium and avail ourselves of other sort attributes, such as by ascending or descending order:

<xsl:sort select="./title | ./info/title" order="descending"/>

We can also sort by data-type, which takes on any of values text (default), number, or qname:

<xsl:sort select="./title | ./info/title" data-type="text"/>
Pulling and Re-ordering by the Numeric Value of an Attribute

If all title elements bore a ordering attribute with a numeric value (or any other attribute with a numeric value), you could order chapters by the numeric value of that attribute, as in:

<xsl:sort select="@ordering" data-type="number"/>

This enables us to generate differently ordered sequences, as many as our chapter elements bore numeric-valued attributes:

<chapter id="my-chapter" ordering="21" scrambled-ordering="4" easy-ordering="7">
  ...
</chapter>

We may even avail ourselves of the presence or absence of an attribute in chapter to pull it in or not:

<xsl:for-each select='//chapter[@special-ordering]'>
  <xsl:sort select="@special-ordering" data-type="number"/>

Pull Advantages?

Keeping the program logic for multiple classes of nodes in one template rule can be an advantage if you want to perform some specific steps on each node type, as well as some other steps on all those nodes. For example, let's say I want to wrap every member element from the following sample document in a p element.

<members>
  <member joinDate="2003-10-03">Jimmy Osterberg</member>
  <member joinDate="2005-03-07">Declan McManus</member>
  <member joinDate="2003-10-03">Richard Starkey</member>
  <member joinDate="2004-08-23">Vincent Furnier</member>
</members>

I want to precede each with a p element that says (founding member) if the joinDate date equals 2003-10-03, and with a p element of (new member) if the joinDate attribute begins with 2005. The following does this easily in a single template rule:

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

  <xsl:template match="member">

    <xsl:if test="@joinDate='2003-10-03'">
      <p>(founding member)</p>
    </xsl:if>

    <xsl:if test="substring(@joinDate,1,4) = '2005'">
      <p>(new member)</p>
    </xsl:if>

    <p><xsl:apply-templates/></p>

  </xsl:template>

</xsl:stylesheet>

XSLT 2.0: New Options

XSLT 2.0 offers another approach. The xsl:next-match element tells the XSLT processor to find the next most applicable template rule for the context node being processed and apply it, letting you apply multiple template rules to a node while still using a push approach. Normally, when multiple template rules all have match conditions that can describe the same element (for example, if one template rule has a match condition of *, another has one of member, and another has one of member[@joinDate='2003-10-03'], they can all apply to the first member element shown above), the XSLT processor applies the one with the most specific description to the node—in this case, the one with a match condition of member[@joinDate='2003-10-03']. (The choice is actually made based on a priority number to help judge how specific the description is. You can override this by explicitly setting a priority attribute value in the template rule.)

While an XSLT processor processes a particular node in a template rule, the xsl:next-match instruction tells it, Go find the next most appropriate template rule after this one, execute all of its instructions, and then resume in this template rule. This lets you rewrite the stylesheet above like this, with the same effect:

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

    <xsl:template match="member[@joinDate='2003-10-03']">
      <p>(founding member)</p>
      <xsl:next-match/>
    </xsl:template>

    <xsl:template match="member[substring(@joinDate,1,4) = '2005']">
      <p>(new member)</p>
      <xsl:next-match/>
    </xsl:template>

    <xsl:template match="member">
      <p><xsl:apply-templates/></p>
    </xsl:template>

</xsl:stylesheet>

When either the first or second template rule here is triggered, it outputs the p element shown and then triggers the third template rule.

It's best to use short examples in this kind of article, and the examples above are so short that the difference between the last two stylesheets seems trivial. You'll find that the usefulness of the xsl:next-match instruction becomes clearer as the amount of program logic to execute scales up. When you have different combinations of large blocks of instructions to execute on a set of nodes, putting these blocks inside of xsl:if instructions or the xsl:when children of xsl:choose elements makes a stylesheet increasingly difficult to read. When you combine the conditional processing made possible by carefully chosen match conditions with the template rule chaining allowed by xsl:next-match, you can have a much more elegant, readable solution. For even greater control over the relationship between the calling and the called templates, you can add xsl:with-param children to the xsl:next-match element to pass parameters, just like you can with named templates.

Splitting Up Output Into Multiple Files

A classic XML transformation task is the splitting of a large source document into multiple result documents. For example, when preparing a large book for web delivery, you probably want to split it up so that each chapter gets converted to a separate HTML file, because the entire book would be too large to send to a web browser.

The XSLT 1.0 specification has no provisions for splitting up output into multiple documents. This ability is so useful, however, that nearly every XSLT processor offers an extension element that lets you do this.

Instead of picking one XSLT processor's syntax for splitting up output documents, or trying to cover all of them, this section shows the syntax for doing so with the xsl:document element described in the W3C 's XSLT 1.1 Working Draft. Although the W3C XSL Working Group eventually decided to discontinue work on XSLT 1.1 in order to fully devote their energy to XSLT 2.0, XSLT 1.1's xsl:document element is based on several existing implementations of this potential XSLT feature and will provide a model for future implementations until a XSLT 2.0 Recommendation eventually makes the xsl:document syntax official.

The following stylesheet converts our document into a set of HTML files:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
  <xsl:template match="chapter">
    <xsl:variable name="chapNum"><xsl:number/></xsl:variable>
    <xsl:document href="chap{$chapNum}.html">
      <html><body>
        <xsl:apply-templates/>
      </body></html>
    </xsl:document>
  </xsl:template>
  <xsl:template match="chapter/title">
    <h1><xsl:apply-templates/></h1>
  </xsl:template>
  <xsl:template match="para">
    <p><xsl:apply-templates/></p>
  </xsl:template>
</xsl:stylesheet>

The <xsl:document Element

Program Control

You can go through a set of nodes one by one, iterating over those nodes, by applying templates to them with xsl:apply–templates. You can also iterate over a set of nodes using xsl:for–each. As a result, the content of the xsl:for–each is processed with each of the nodes as the current node. With both instructions, the nodes are usually processed in document order, but you can change the order using xsl:sort.

xsl:if

It relies on a test attribute.

<xsl:if test="not(@author='anonymous')">
  Book written by <xsl:value-of select='@author'/>
</xsl:if>

xsl:choose

XSLT's xsl:choose instruction is similar to xsl:if but with a few key differences:

  • One xsl:choose element can test for more than one condition and add different nodes to the result tree based on which condition is true.
  • An xsl:choose element can have a default template to add to the result tree if none of the conditions are true. (Compare to xsl:if , which has no equivalent of an "else" condition.)
  • The xsl:choose element has specific subelements necessary for it to work. You can put any well-formed elements you want inside of an xsl:if element.

When an XSLT processor sees an xsl:choose element, it checks the test attribute value of each xsl:when element that it finds as a child of the xsl:choose element. When it finds a true test expression, it adds that xsl:when element's contents to the result tree and then skips the rest of the xsl:choose ele- ment. If it finds no xsl:when element with a true test expression, it checks for the optional xsl:otherwise element at the end of the xsl:choose element. If it finds one, it adds its contents to the result tree.

An example:

<xsl:template match="poem">
  <xsl:choose>
    <xsl:when test="@year &lt; 1638">
      The poem is one of Milton&apos; earlier works.
    </xsl:when>
    <xsl:when test="@year &lt; 1650">
      The poem is from Milton&apos; middle period.
    </xsl:when>
    <xsl:when test="@year &lt; 1668">
      The poem is one of Milton&apos; later works.
    </xsl:when>
    <xsl:when test="@year &lt; 1675">
      The poem is one of Milton&apos; last works.
    </xsl:when>
    <xsl:otherwise>
      The poem was written after Milton&apos; death.
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Curly braces

For some stylesheet attribute values, curly braces tell the XSLT processor to evaluate the expression between them and to replace the curly braces and their contents with the result of that evaluation. The following stylesheet demonstrates the effect of the curly braces:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
  <test>
    <xsl:variable name="myVar">10</xsl:variable>
      A. <atvtest at1="hello world"/>
      B. <atvtest at1="3+2+$myVar"/>
      C. <atvtest at1="{3+2+$myVar}"/>
      D. <atvtest at1="yo, substring('hello world',7)"/>
      E. <atvtest at1="yo, {substring('hello world',7)}"/>
    </test>
  </xsl:template>
</xsl:stylesheet>

References to variables inside of curly braces get converted to the value they represent, but when they have no curly braces around them, the reference to the variable is treated as literal text.

Iteration and Loops

Programming languages use loops to execute an action or series of actions several times. After performing the last action of such a series, the program "loops" back up to the first one. The program may repeat these actions a predetermined number of times or it may repeat the actions until a specified condition is true.

  • The xsl:for-each instruction lets you perform the same group of instructions on a given set of nodes.
  • By having a named template call itself recursively with parameters, you can execute a series of instructions for a fixed number of times or until a given condition is true. The technique may not be familiar to programmers accustomed to the "for" and "while" loops available in languages such as Java, C, and C++, but it can perform the same tasks.

Here is some code to list all the figures in a chapter before it starts:

<xsl:template match="chapter">
  Pictures:
  <xsl:for-each select="descendant::figure">
    <xsl:value-of select="title"/><xsl:text>
    </xsl:text>
  </xsl:for-each>
  Chapter:<xsl:apply-templates/>
</xsl:template>

Another advantage of acting on a set of nodes with an xsl:for-each element instead of with an xsl:template element lies in a limitation to template rules that XSLT novices often don't notice: while it may appear that you can use XPath expressions in an xsl:template element's match attribute, you're actually limited to the subset of XPath expressions known as patterns. In the xsl:for-each element's select attribute, however, you have the full power of XPath expressions available.

For example, you can't use the ancestor axis specifier in match patterns, but you can do so in an xsl:for-each element's select attribute. The following template uses the ancestor axis specifier to list the names of all a title element's ancestors:

<xsl:template match="title">
  <xsl:text>title ancestors:</xsl:text>
  <xsl:for-each select="ancestor::*">
    <xsl:value-of select="name()"/>
    <!-- Output a comma if it&apos; not the last one in the node set that for-each is going through. -->
    <xsl:if test="position() != last()">
      <xsl:text>,</xsl:text>
    </xsl:if>
  </xsl:for-each>
  </xsl:template>
<xsl:template match="para"/>

To execute a piece of code a specific number of times you have to use recursion, as in:

<xsl:template name="hyphens">
  <xsl:param name="howMany">1</xsl:param>
  <xsl:if test="$howMany &gt; 0">
    <!-- Add 1 hyphen to result tree. -->
    <xsl:text>-</xsl:text>
    <!-- Print remaining ($howMany - 1) hyphens. -->
    <xsl:call-template name="hyphens">
      <xsl:with-param name="howMany" select="$howMany - 1"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template match="sample">
  Print 1 hyphen:
  <xsl:call-template name="hyphens"/>
  Print 3 hyphens:
  <xsl:call-template name="hyphens">
    <xsl:with-param name="howMany" select="3"/>
  </xsl:call-template>
</xsl:template>

Generating Output

To create a simple text string we use xsl:text when we need complete control over whitespace or when we're creating text output instead of a marked-up document.

Handling Space Through XSLT

You probably want to normalize space. Use normalize-space().

Eliminating Redundant Space

Use normalize-space(), which is a function that removes extra whitespace from its argument string. Its output is a string with whitespace removed as follows:

  • All leading whitespace is removed.
  • All trailing whitespace is removed.
  • Within the string, any sequence of whitespace characters is replaced with a single space

A simple example:

<xsl:template match="text()">
  <xsl:value-of select="normalize-space()"/>
</xsl:template>

Preserving and Stripping Space

The <xsl:preserve-space> element is used to define the elements for which white space should be preserved when no other characters are used. The <xsl:strip-space> element is used to define the elements for which white space should be removed.

The number element

The xsl:number element is used to number the parts of a document or to format a numeric value. In general, xsl:number counts something.

<xsl:for-each select="cars/manufacturer">
  <p>
    <xsl:number format="1. "/>
    <xsl:value-of select="@name"/>
  </p>
</xsl:for-each>

or:

<xsl:for-each select="cars/manufacturer">
  <p>
    <xsl:text>Cars produced by </xsl:text>
    <xsl:value-of select="@name"/>
    <xsl:text>: </xsl:text>
    <xsl:number value="count(car)" format="01"/>
  </p>
</xsl:for-each>

or setting the level attribute to "multiple":

<xsl:for-each select="book/chapter">
  <xsl:number count="chapter" format="1. "/>
  <xsl:value-of select="title"/>
  <xsl:text>&#xA;</xsl:text>
  <xsl:for-each select="sect1">
    <xsl:number count="chapter|sect1" level="multiple" format="1.1. "/>
    <xsl:value-of select="."/>
    <xsl:text>&#xA;</xsl:text>
  </xsl:for-each>
</xsl:for-each>

XSLT 2.0 also adds the ordinal attribute; ordinal="yes" combined with format="1" generates 1st , 2nd , 3rd , while ordinal="yes" combined with format="Ww" generates First , Second , Third . The ordinal attribute has many different options that depend on the lang attribute and the format attribute; as you would expect, each XSLT 2.0 processor supports a different set of languages and options for the ordinal attribute. See your processor's documentation for information on what capabilities are available.

The sort element

<xsl:for-each select="dfn">
<xsl:sort select="."/>

The value-of element

To output the value of something from the XML source we use xsl:value-of select="...".

Using xsl:copy and xsl:copy-of

As you transform your XML input document into something else, you'll often want to just copy a given element to the output document:

xsl:copy-of

does a deep copy of a node, so the root node and all of its children are copied to the output. If any of the root node's descendants are element nodes with attributes, the attributes are copied as well. (Remember, an element's attributes aren't considered children.)

xsl:copy

Using xsl:copy to copy our document requires using the xsl:for-each element to copy all the attributes of each element we're copying. It forces you do to most of the work yourself, but you have complete control over what exactly gets copied.

To really understand the power of xsl:copy-of, let's compare it to the xsl:value-of instruction. Both help you grab an arbitrary part of the source tree while the XSLT processor is processing another part of the tree. The xsl:value-of element doesn't add a copy of the grabbed node to the result tree, but a text node with a string representation of it. When xsl:value-of is told to convert a set of nodes to a string, it only gets the first one in that set, so it's only useful for getting one node's value at a time. The xsl:copy-of element, on the other hand, gets a whole node set and all of the nodes' children.

Handling space

Use xsl:preserve-space elements="pre literallayout"/ or xsl:strip-space elements="para title"/.

To clean up the whitespace, we can use the normalize-space( ) function. It does three things:

  • it removes all leading spaces,
  • it removes all trailing spaces, and
  • it replaces any group of consecutive whitespace characters with a single space.
<xsl:template match="text()">
  <xsl:value-of select="normalize-space()"/>
</xsl:template>

Grouping Nodes

When grouping nodes, we sort things to get them into a certain order, and then we group all items that have the same value for the sort key (or keys). We'll use xsl:sort for this grouping, and then use variables or functions such as key( ) or generate-id( ) to finish the job.

Translating Characters with string xsl:translate(s1, s2, s3) function

This function returns a string where all characters in s1 are returned as such save for those in s2. Those in s2 are returned as in s3. translate() will not copy characters in the input string that are in the from string but do not have a corresponding character in the to string.

If you want to strip certain characters (e.g., whitespace) from a string, you might use translate() with an empty replace string. For example, the following code can strip whitespace from a string:

translate($input," &#x9;&#xa;&xd;", "")
Removing All But a Specific Set of Characters

You can also use translate() to remove all but a specific set of characters from a string. For example, the following code removes all non-numeric characters from a string:

translate($string,
          translate($string,'0123456789',''),'')

The inner translate() removes all characters of interest (e.g., numbers) to obtain a from string for the outer translate(), which removes these non-numeric characters from the original string.

Variables, Parameters, and Keys

Variables

Variables are declared with xsl:variable. The two types of variables are local variables, which are defined within templates and only accessible within that template, and global variables, which are defined at the top level of the stylesheet and are accessible anywhere. A local variable cannot have its value reassigned, but global variables can be overridden by local variables.

Variables can be set in two ways. First, they can be set through the select attribute. Second, they can be set through content of xsl:variable. Setting a variable through its content always sets it to a result tree fragment.

The select attribute can set a variable to any value type.

A variable in XSLT has more in common with a variable in algebra than with a variable in a typical programming language. A variable is a name that represents a value and, within a particular application of a template, it will never represent any other value: it can't be changed. XSLT variables actually have a lot more in common with something known as "constants" in many programming languages, and variables are used for a similar purpose as constants.

The xsl:variable instruction creates a variable. Its name attribute identifies the variable's name. The value can be specified either as the xsl:variable element's contents (like the "10pt" in the example) or as the value of an optional select attribute in the xsl:variable element's start-tag.

<xsl:variable name="HeaderTextSize">20pt</xsl:variable>
<xsl:template match="title">
  <b><font size="{$HeaderTextSize}">
    <xsl:apply-templates/>
  </font></b><br/>
</xsl:template>

Alternatively, you can use the select attribute to set the value of a variable:

<xsl:variable name="baseFontSize" select="12"/>
<xsl:variable name="HeaderTextSize" select="concat($baseFontSize+8,'pt')"/>

Parameters

Parameters are defined by xsl:param and work in much the same way as variables, except that the value of a parameter may be overridden by having another value passed to it. The value defined by the select attribute or content of xsl:param is the default value of the parameter, and is used when no other value is passed to it from outside.

Parameters that are defined within templates must occur before anything else within the template. These local parameters can be overridden when the template is applied or called using xsl:with–param within xsl:apply–templates or xsl:call–template. Parameters are passed by name — the name attribute of xsl:with–param indicates the parameter that it defines the value of. As with variables and default parameter values, the xsl:with–param element can set a value either through the select attribute or through its content. Parameters that are defined at the top level of the stylesheet are global parameters. The XSLT Recommendation doesn't say anything about how global parameters are given values — each XSLT processor sets global parameters in a different way.

The xsl:param instruction is just like xsl:variable , with one important difference: its value is only treated as a default value and can be overridden at runtime.

How do you pass the alternative value for the parameter to the stylesheet? The official XSLT spec doesn't tell us!

How we pass a new value to a template rule's local parameter isn't quite the open question that it is with global parameters, because XSLT provides the xsl:with-param instruction for just this purpose. You can use this element in an xsl:apply-templates element to assign a new value to a parameter in a template being applied, but it's more commonly used when calling a named template with the xsl:call-template instruction.

<xsl:template name="titles">
  <xsl:param name="headerElement">h4</xsl:param>
  <xsl:element name="{$headerElement}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="chapter/title">
  <xsl:call-template name="titles">
    <xsl:with-param name="headerElement">h1</xsl:with-param>
  </xsl:call-template>
</xsl:template>

<xsl:template match="sect1/title">
  <xsl:call-template name="titles">
    <xsl:with-param name="headerElement" select="'h2'"/>
  </xsl:call-template>
</xsl:template>

<xsl:template match="para">
  <p><xsl:apply-templates/></p>
</xsl:template>

<xsl:template match="chapter">
  <html><body><xsl:apply-templates/></body></html>
</xsl:template>

Declaring Keys To Perform Lookups

Keys create a hashtable that enables you to access nodes quickly. They are defined by xsl:key at the top level of the stylesheet. When a key is created, the processor works through the current document, finding all the nodes that match the pattern given in the match attribute of the xsl:key. Each of these nodes is stored in a hashtable and indexed by one or more key values. The key values are identified by evaluating the expression held in the use attribute of the xsl:key for the node as a string. However, if this expression returns a node set, the node is indexed by the string values of each of the nodes, rather than by just the first node in the node set. Using keys can greatly add to the efficiency of your stylesheet. They are also a vital component of some methods for grouping.

When you need to look up values based on some other value—especially when your stylesheet needs to do so a lot—XSLT's xsl:key instruction and key() function work together to make it easy. They can also make it fast.

Given:

<shirts>
  <colors>
    <color cid="c1">yellow</color>
    <color cid="c2">black</color>
    <color cid="c3">red</color>
    <color cid="c4">blue</color>
    <color cid="c5">purple</color>
    <color cid="c6">white</color>
    <color cid="c7">orange</color>
    <color cid="c7">green</color>
  </colors>

  <shirt colorCode="c4">oxford button-down</shirt>
  <shirt colorCode="c1">poly blend, straight collar</shirt>
  <shirt colorCode="c6">monogrammed, tab collar</shirt>
</shirts>

And we want to produce:

blue oxford button-down
yellow poly blend, straight collar
white monogrammed, tab collar

So we write a stylesheet like:

<xsl:key name="colorNumKey" match="color" use="@cid"/>
<xsl:template match="colors"/>
<xsl:template match="shirt">
  <xsl:value-of select="key('colorNumKey',@colorCode)"/>
  <xsl:text> </xsl:text><xsl:apply-templates/>
</xsl:template>

The xsl:key element has three attributes:

  • The name attribute holds the name of the lookup key. The key() function uses this name to identify what kind of lookup it's doing.
  • The match attribute holds a match pattern identifying the collection of nodes where the lookups will take place. In the example, the color elements are this collection. The fact that they are enclosed by a colors element gives the source document a little more structure, but it's not necessary for the key lookups to work. And
  • The use attribute specifies the part or parts of the match attribute's collection of nodes that will be used to find the appropriate node—in other words, the attribute specifies the index of the lookup. In the example, this index is the cid attribute of the color elements, because a lookup will pass along a color ID string to look up the corresponding color.

No doubt these color elements would fit nicely into a table, but the beauty of doing so with XSLT (and XML) is that the elements named by your match attribute can have much more complex structures than any relational database table row. You have the full power of XML available, and the ability to use an XPath expression in the use attribute lets you identify any part of that structure you want to use as the lookup key.

The key() function performs the actual lookup. This function takes a value, searches through the keys for one whose use value equals the one it's looking for, and returns the element or elements that have that key value.

XSLT and Entities

An example of declaring and using an entity:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [<!ENTITY netsi "netsi1964@gmail.com">]>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

  <xsl:output method="xml" indent="no"/>

  <xsl:template match="/">
    <h1>&amp;netsi; bliver til "&netsi;"</h1>
  </xsl:template>
</xsl:stylesheet>

...

XSL Recipes

Short Path Snippets

Select all chapters whose title starts with the string C++:

<xsl:apply-templates select="chapter[starts-with(title, 'C++')]" />

To select all chapter elements but the third one:

<xsl:apply-templates select="Channel[position() &lt;= 3  or position() >= 5]" />

To select all chapter elements between the third and the ninth:

<xsl:apply-templates select="Channel[position() >= 3  and position() &lt;= 9]" />

or just:

<xsl:apply-templates select="Channel[position() = (3 to 9)]" />

The contains() function, like all other functions in XPath, is case-sensitive. You can do a case-insensitive search for a word within a string by making sure both strings use the same case throughout. You can translate elements into lowercase using the lower-case() function:

contains(lower-case(title), "HTML")

...

<xsl:analyze-string select="poem" regex="\n">
  <xsl:matching-substring>
    <br />
  </xsl:matching-substring>
  <xsl:non-matching-substring>
    <xsl:value-of select="normalize-space(.)" />
  </xsl:non-matching-substring>
</xsl:analyze-string>

Copying all Elements with either copy or copy-of

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"/>
  <!-- Copy all elements, attributes, and text nodes -->
  <xsl:template match="*|@*|text()|comment()">
    <xsl:copy>
      <xsl:apply-templates select="*|@*|text()|comment()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Much the same, but using copy-of:

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

  <!-- Copy all the other elements and attributes, and text nodes -->
  <xsl:template match="*|@*|text()|comment()">
     <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>

Not very useful per se, this code is included in other stylesheets.

Excluding Elements Selectively

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"/>
<xsl:template match="*[@class='private']"> <xsl:comment>private</xsl:comment> </xsl:template>
<!-- Copy all the other elements and attributes, and text nodes -->
<xsl:template match="*|@*|text()">
  <xsl:copy>
    <xsl:apply-templates select="*|@*|text()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Hiding Elements Selectively

You may want to exclude all elements whose class attribule has value private.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"/>
 <xsl:template match="*[@class='private']">
    <xsl:comment>
      <xsl:copy-of select="self::*"/>
    </xsl:comment>
  </xsl:template>
  <!-- Copy all the other elements and attributes, and text nodes -->
  <xsl:template match="*|@*|text()">
    <xsl:copy>
      <xsl:apply-templates select="*|@*|text()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Numbering Chapters Automatically

To number the title of each chapter from 1. onwards, add these templates to the copy all template. Notice how the first, short template inhibit ordinary handling of chapter titles.

<xsl:template match="chapter/title"/>
<xsl:template match="chapter">
  <chapter>
    <title>
      <xsl:number format="1. "/> <xsl:value-of select="title" />
    </title>
    <xsl:apply-templates />
  </chapter>
</xsl:template>

Numbering Chapters and Sections (2 Levels Thereof) Automatically

Add these templates to the copy all template and study the code, too:

<xsl:template match="chapter/title"/>
<xsl:template match="chapter">
  <chapter>
    <title>
      <xsl:number format="1. "/> <xsl:value-of select="title" />
    </title>
    <xsl:apply-templates />
  </chapter>
</xsl:template>

<xsl:template match="sect1/title"/>
<xsl:template match="sect1">
  <section>
    <title>
      <xsl:number format="1. " level="multiple" count="chapter|sect1"/>
      <xsl:value-of select="title" />
    </title>
    <xsl:apply-templates/>
  </section>
</xsl:template>

<xsl:template match="sect2/title"/>
<xsl:template match="sect2">
  <section>
    <title>
      <xsl:number format="1. " level="multiple" count="chapter|sect1|sect2"/>
      <xsl:value-of select="title" />
    </title>
    <xsl:apply-templates/>
  </section>
</xsl:template>

Sorting (a VariableList by Term)

A DocBook dl holds varlistentry' each holding a term element and a listitem element. Notice how varlistentry is not mentioned in the code. (Whenever the sorting key is numeric, add data-type="number" in the sort opening label.)

<xsl:template match="dl">
  <dl>
  <xsl:apply-templates>
    <xsl:sort select="term" />
  </xsl:apply-templates>
  </dl>
</xsl:template>

Generating HTML from XML

<?xml version='1.0'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method='html'
  indent='yes'
  doctype-public='-//W3C//DTD HTML 3.2 Final//EN'/>
<xsl:template match='/'>
  <HTML>
    <HEAD>
      <TITLE>My Document Title</TITLE>
    </HEAD>
    <BODY>
      <xsl:apply-templates/>
    </BODY>
  </HTML>
</xsl:template>

And so on...

Converting From (Docbook) XML to TeX

We shall be using file book.xml to test our stylesheets on.

          
            
          
        

We might start from a trivial stylesheet file (default.xsl) that just copies all the text nodes:

          
            
          
        

Transforming Entities and Non-Ascii Characters with Sed

We want to transform 'á' to '\'a' and so on. We need a sed script with lines like s/á/\'a/g and so on. Here is our sed script for your eyes' delight:

            
              
            
          

Removing Redundant Space

Next, we would add templates that deal with mark up. We want to remove meaningless whitespace with redundant whitespace to be removed through normalize-space(), as well as printing titles in bold fonts, em in italic, etc. Last, the output must end with \bye:

            
              
            
          

Numbering Chapters Headers

Besides numbering chapters and headers, the xml_to_tex.02.xsl stylesheet also:

  • handles several inline and block elements,
  • handles mathematical formulas where the TeX code has been included inside a alt element: equation, inlineequation, and informalequation, although equation numbering has not been implemented yet.
            
              
            
          

Handling Mathematical Formulas

This is actually done by xml_to_tex.mathematical.xsl, which presumably is included by Electric_files/XSLT_code/xml_to_tex.02.xsl. Here is a listing of xml_to_tex.mathematical.xsl

<xi:include href="Electric_files/XSLT_code/xml_to_tex/xml_to_tex.mathematical.xsl" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude">
          <xi:fallback/>
        </xi:include>

The Trouble with Backslashes and Other Characters ('^', '_', '$', '#', '&', '%', '~', '{', '}'...)

Now, if we translate all the backslashes \ in the original to the sequence \backslash, then we cannot supply TeX code in, say, mathematical elements, or other TeX code containing long TeX commands, such as \obeylines.

We need a method to prevent translating backslashes in xml whenever they are in a given element.

One solution using existing tools is to translate all backslash characters inside an alt elements to another, non-TeX character, such as , then translating it back to a backslash. Use function translate(s, sorigin, sdest).

Here is a file that realizes this:

            
              
            
          

Next, we could write a reverse transformation file (unescape_backslash_in_alt) where '\' and '€' are exchanged.

The procedure then is:

  • change all backslashes in alt sections to an un-TeX character, such as '€'
  • translate all characters through sed and utf8-to-TeX.sed
  • revert all backslash substitutions in alt sections to '\'
  • transform to TeX through stylesheet xml_to_tex.02.xsl or some higher version
  • process your result through application tex or some other means

Handling Lists, aka itemizedlist'''s*

This is a primitive template to handle lists:

<xsl:template match="listitem">
    $\bullet$ <xsl:apply-templates/>

  </xsl:template>

The problem remains of \bullet getting mangled to \backslash bullet by the sed script. One solution is for the XSLT transformation to use an euro sign instead of a backslash, i.e. €bullet, and then have another sed script to translate all euro signs back to slashes.

Actually, we should do the same for all TeX commands introduced by the XSLT translation. In reverting the backslash substitutions, we no longer select for text in alt elements. The procedure now comprises the following steps:

  • change all backslashes in alt sections to an un-TeX character, such as '€'
  • translate all characters through sed and utf8-to-TeX.sed
  • revert all backslash substitutions (not necessarily only those in alt sections) to '\'
  • transform to TeX through stylesheet xml_to_tex.02.xsl or some higher version
  • process your result through application tex or some other means