LanguagesXMLDiscover the Wonders of XSLT: Advanced Techniques

Discover the Wonders of XSLT: Advanced Techniques

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Welcome to the third installment of Developer.com’s introduction to XSLT.

The first two parts (Part One and Part Two) have introduced the most fundamental XSLT instructions:

  • templates and loops as a means to transform an XML document into either HTML or another XML document
  • XPaths and predicates as a querying language to extract data from an XML document

Together, the first two parts cover 70% of XSLT coding needs and you write many fine stylesheets using only these techniques. This month, we will cover more advanced techniques that simplify XSLT coding.

Tests

One could argue that we have covered testing already through predicates. Yet there are cases where a simple if/then/else would do the job faster and more cleanly than predicates.

XSLT offers two instructions for tests:

  • xsl:if is the standard if statement
  • xsl:choose is a switch statement that allows you to combine multiple tests and implement if/then/else

The simplest test looks like the following:

<xsl:if test="count(a:para) > 1">
   <p><xsl:value-of select="count(a:para)"/> paragraphs</p>
</xsl:if>

As the name implies, the test attribute holds… the test. The processor will output the content of the xsl:if element if test evaluates to true.

The content can be any combination of text literal, XML elements, and XSLT instructions.

The xsl:choose statement is a more sophisticated test, as follows:

<xsl:choose>
   <xsl:when test="not(a:para)">
      <p>no paragraphs</p>
   </xsl:when>
   <xsl:when test="count(a:para) = 1">
      <p>one paragraph</p>
   </xsl:when>
   <xsl:otherwise>
      <p><xsl:value-of select="count(a:para)"/> paragraphs</p>
   </xsl:otherwise>
</xsl:choose>

The processor will output the content of the first xsl:when whose test attribute evaluates to true or, failing that, the content of xsl:otherwise.

Be careful with the order of xsl:when statements because the processor will output the first one that is true only. Also, the xsl:otherwise statement is optional.

To implement an if/then/else statement, you could use an xsl:choose with a single xsl:when and a single xsl:otherwise.

A quick tip: The empty node set evaluates to false so to test for the presence of an element, it suffices to write the appropriate XPath in the test attribute. If the element exists, the XPath will return a non-empty node set; if the element does not exist, the XPath will return an empty node set. In the above example, I use the technique in the first xsl:when.

Generating Output: Text Literals

So far, in templates, loops, and tests, you learned to write the text literals and XML instructions as you want them to appear in the output. A typical template mixes text literals, XML elements, and XSLT statements:

<xsl:template match="a:body">
   <body>
      <h1><xsl:value-of select="../a:info/a:title"/></h1>
      <h2>Table of Contents</h2>
      <ul>
         <xsl:for-each select="a:section">
            <li><xsl:value-of select="a:title"/></li>
         </xsl:for-each>
      </ul><hr/>
      <xsl:apply-templates/>
      <p>This page was made with XML and XSLT.</p>
   </body>
</xsl:template>

There are cases where you need more control over the output. XSLT offers special instructions to generate text literals, elements, and attributes.

xsl:text is an XSLT statement that generates a text literal. It is mostly identical to just typing the text literal with one simple difference: xsl:text preserves the spaces.

The XSLT processor will normalize most text literals which is the sensible behavior in most cases. Uf you absolutely need the spaces though, use xsl:text.

In practice, the most common application of xsl:text is the following:

<xsl:text> </xsl:text>

to insert one blank space (without the xsl:text instruction, the processor could remove the space as part of the normalization process).

Generating output: attributes

xsl:attribute adds an attribute to the current element. In most cases, you just want to write the attribute as a literal, like this:

<a href="{@uri}">

But xsl:attribute is an XSLT statement, so it can appear wherever a statement can appear. It is useful mostly for tests. The following example marks hyperlinks to my Web site in red:

<a href="{@uri}">
<xsl:if test="starts-with(@uri,'http://www.marchal.com')">
   <xsl:attribute name="style">color: red;</xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</a>

The xsl:attribute has a name parameter with the attribute’s name and an optional namespace parameter with the attribute’s namespace.

xsl:attribute must appear before any other children; it is a mistake to insert a text literal or any instruction that will insert text before xsl:attribute. I like to think that the processor has not yet closed the start tag (>) when it encounters the xsl:attribute statement.

Generating Output: elements

For completeness, note that the xsl:element statement exists. It is mostly similar to xsl:attribute, but it is seldom needed in practice. About the only sensible application is to compute an element name:

<xsl:element name="record-{position()}">
   <xsl:apply-templates/></xsl:element>

Output

While we’re on the matter of generating output, let’s return to the very instruction in any xsl:output stylesheet.

As you learned in Part 1, xsl:output controls whether the processor generates an HTML, text, or XML document.

xsl:output supports more attributes that give you a lot of control over the output document. The most useful attributes are:

  • encoding, which specifies the encoding. The default is UTF-8, but you can specify any valid encoding, such as UTF-16, ISO-8859-1 (Latin-1), and more.
  • indent set to yes tells the processor to indent the code. This is handy for debugging.
  • doctype-public and doctype-system control the DOCTYPE statement required by some XML vocabularies.
  • omit-xml-declaration removes the XML declaration from the output document. It is not used often.

Testing and Exercise

I encourage you to download the listing and take the exercise. It’s your chance to practice what you have learned.

Remember to adapt the processing instruction, as explained in Part 1, if you change the style sheet in the exercise.

Next month, we will review and compare styles of stylesheet coding.

About the Author

Benoît Marchal is a Belgian writer and consultant. He is the author of XML by Example and other XML books. He works mostly on Web services, XML, and Java.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories