Classes and methods are the tools that object-oriented programmers use to organize a large application into smaller, more manageable units. XSLT programmers use templates for the same purpose. The processor hands control to a template when its pattern matches the current node.
This pattern matching mechanism is particularly well suited to processing trees (like XML documents). It leads to a declarative style of programming because it saves having to write all the tree walking and tree manipulation routines. Instead, the processor walks the input document and automatically selects the most appropriate template for the nodes.
Pattern matching is particularly handy when you don't know in which order the elements appear in the input document or whether they are repeated. Again, the processor takes care of the repetition by calling your template repetitively.
Most templates are written to match elements. When a stylesheet processes attributes, the rule is often attached to a template matching an element, as in Listing 1 (all examples in this article are excerpted from a DocBook-to-HTML stylesheet):
Listing 1. Processing an attribute attached to an element
<xsl:template match="ulink">
<a href="{@url}"><xsl:apply-templates/></a>
</xsl:template>
|
This template transforms the ulink element and url attribute, but it matches against the ulink element only.
Matching against the element makes sense if the attribute is required -- in other words, if it must be present. However, if the attribute is optional you'd want to test whether it exists before generating anything in the output. In some cases, you'd want to test through a condition in the pattern, such as in Listing 2:
Listing 2. Testing for an attribute in a template match
<xsl:template match="emphasis[@type='bold']">
<b><xsl:apply-templates/></b>
</xsl:template>
|
Testing for attributes is not always practical. Take a look at the markup for an image -- imagedata in DocBook. imagedata has optional width and depth attributes that you might want to save in HTML. It would be too difficult to code for all the possible combinations (imagedata[@width], imagedata[@depth], and imagedata[@width and @depth] -- that's three templates for only two attributes). It's more sensible to let the processor walk through the attribute nodes and write templates against them, as shown in Listing 3:
Listing 3. Templates matching attributes
<xsl:template match="imagedata">
<img><xsl:apply-templates select="@*"/></img>
</xsl:template>
<xsl:template match="@width">
<xsl:attribute name="width">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="@depth">
<xsl:attribute name="height">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="@fileref">
<xsl:attribute name="href">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
|
Note that by default, the processor does not walk the attribute nodes. You have to ask for that explicitly with a select="@*" attribute.
Two important differences between templates matching elements and templates matching attributes are:
-
Attributes are leafs. An
xsl:apply-templatesinstruction gets you nowhere because attributes have no children for the processor to walk through. Usexsl:value-ofinstead. -
Most attributes in the input are also attributes in the output. Use
xsl:attributeto insert an attribute in the output tree. Be careful, though --xsl:attributemust appear before any other children. In other words, thexsl:apply-templatesinstruction must come before any text or child elements in the caller.
Matching on attributes gives you the full expressiveness of XSLT. Templates are not limited to turning an attribute into another attribute. You can add conditions to the pattern or turn attributes into elements. The template in Listing 4 defines a special rule to match fileref as an attribute of videodata. It creates an element instead of an attribute.
Listing 4. Matching on an attribute with a condition
<xsl:template match="videodata/@fileref">
<param name="src" value="{.}"/>
</xsl:template>
|
Also, in the caller you can apply templates to attributes as well as the element content with a select="@* | node()" attribute, as in Listing 5:
Listing 5. The calling template processes elements and attributes
<xsl:template match="para">
<p><xsl:apply-templates select="@* | node()"/></p>
</xsl:template>
|
This tip is a practical example of a more generic rule in XSLT coding: To make your stylesheet more maintainable, it pays to divide the work among several templates.
- Participate in the discussion forum for Benoit Marchal's Working XML column.
- Try Xalan, available on The Apache XML Project site. Xalan remains one of the most popular XSL processors.
- Visit the XSL FAQ, maintained by Dave Pawson, for a good source of answers to common questions.
- If you've been bitten by the XSL virus, you'll love the Gallery of Stupid XSL and XSLT Tricks, a compilation of unusual and amusing tricks with (you guessed it) XSL/XSLT.
- Take an introductory tutorial to XSLT -- "Manipulating data with XSL" by Nicholas Chase (developerWorks, October 2001).
- Read "What kind of language is XSLT?"
for Michael Kay's discussion of the XSLT language and its implementation of templates (developerWorks, February 2001).
- Find more XML resources on the developerWorks
XML zone. For a complete list of XML tips to date, check out the tips summary page.
- Find out how you can become an IBM Certified Developer in XML and related technologies.

Benoit Marchal is a Belgian consultant. He is the author of XML by Example, Second Edition and other XML books. Benoit is available to help you with XML projects. You can contact him at bmarchal@pineapplesoft.com or through his personal site at marchal.com.