Book HomeXSLSearch this book

2.4. Stylesheet Structure

As the final part of our introduction to XSLT, we'll look at the contents of the stylesheet itself. We'll explain all the things in our stylesheet and discuss other approaches we could have taken.

2.4.1. The <xsl:stylesheet> Element

The <xsl:stylesheet> element is typically the root element of an XSLT stylesheet.

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

First of all, the <xsl:stylesheet> element defines the version of XSLT we're using, along with a definition of the xsl namespace. To be compliant with the XSLT specification, your stylesheet should always begin with this element, coded exactly as shown here. Some stylesheet processors, notably Xalan, issue a warning message if your <xsl:stylesheet> element doesn't have these two attributes with these two values. For all examples in this book, we'll start the stylesheet with this exact element, defining other namespaces as needed.

2.4.2. The <xsl:output> Element

Next, we specify the output method. The XSLT specification defines three output methods: xml, html, and text. We're creating an HTML document, so HTML is the output method we want to use. In addition to these three methods, an XSLT processor is free to define its own output methods, so check your XSLT processor's documentation to see if you have any other options.

<xsl:output method="html"/>

A variety of attributes are used with the different output methods. For example, if you're using method="xml", you can use doctype-public and doctype-system to define the public and system identifiers to be used in the the document type declaration. If you're using method="xml" or method="html", you can use the indent attribute to control whether or not the output document is indented. The discussion of the <xsl:output> element in Appendix A, "XSLT Reference" has all the details.

2.4.3. Our First <xsl:template>

Our first template matches "/", the XPath expression for the document's root element.

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

2.4.4. The <xsl:template> for <greeting> Elements

The second <xsl:template> element processes any <greeting> elements in our XML source document.

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

2.4.5. Built-in Template Rules

Although most stylesheets we'll develop in this book explicitly define how various XML elements should be transformed, XSLT does define several built-in template rules that apply in the absence of any specific rules. These rules have a lower priority than any other templates, so they're always overridden when you define your own templates. The built-in templates are listed here.

2.4.5.1. Built-in template rule for element and root nodes

This template processes the root 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>

This means that if the structure of a document looks like this:

<?xml version="1.0"?>
<x>
  <y>
    <z/>
  </y>
</z>

The built-in template rule for element and root nodes means that we could write a template with match="z" and the <z> element will still be processed, even if there are no template rules for the <x> and <y> elements.

2.4.5.2. Built-in template rule for modes

This template ensures that element and root nodes are processed, regardless of any mode that might be in effect. (See Section 4.3.2, "Templates à la Mode" in Chapter 4, "Branching and Control Elements" for more information on the mode attribute.)

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

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

2.4.5.4. Built-in template rule for comment and processing instruction nodes

This template does nothing.

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

2.4.5.5. Built-in template rule for namespace nodes

This template also does nothing.

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

2.4.6. Top-Level Elements

To this point, we haven't actually talked about our source document or how we're going to transform it. We're simply setting up some properties for the transform. There are other elements we can put at the start of our stylesheet. Any element whose parent is the <xsl:stylesheet> element is called a top-level element. Here is a brief discussion of the other top-level elements:

<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:strip-space elements="*"/>
<xsl:preserve-space elements="greeting
            salutation"/>
<xsl:key>
This element defines a key, which is similar to defining an index on a database. We'll talk more about the <xsl:key> element and the key() function in Section 5.2, "Generating Links with the key() Function" in Chapter 5, "Creating Links and Cross-References".

<xsl:variable>
This element defines a variable. Any <xsl:variable> that appears as a top-level element is global to the entire stylesheet. Variables are discussed extensively in Section 4.5, "Variables" in Chapter 4, "Branching and Control Elements".

<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. Parameters are discussed extensively in Section 4.4, "Parameters" in Chapter 4, "Branching and Control Elements".

Other stuff
More obscure elements that can appear as top-level elements are <xsl:decimal-format>, <xsl:namespace-alias>, and <xsl:attribute-set>. All are discussed in Appendix A, "XSLT Reference".

2.4.7. Other Approaches

One mantra of the Perl community is, "There's more than one way to do it." That's true with XSLT stylesheets, as well. We could have written our stylesheet like this:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0">
  <xsl:output method="html"/>
        
  <xsl:template match="/">
    <html>
      <body>
        <xsl:apply-templates select="greeting"/>
      </body>
    </html>
  </xsl:template>
        
  <xsl:template match="greeting">
    <h1>
      <xsl:value-of select="."/>
    </h1>
  </xsl:template>
</xsl:stylesheet>

In this version, we put the wrapper elements for the HTML document in the template for the root element. One of the things you should think about as you build your stylesheets is where to put elements like <html> and <body>. Let's say our XML document looked like this instead:

<?xml version="1.0"?>
<greetings>
  <greeting>Hello, World!</greeting>
  <greeting>Hey, Y'all!</greeting>
</greetings>

In this case, we would have to put the <html> and <body> elements in the <xsl:template> for the root element. If they were in the <xsl:template> for the <greeting> element, the output document would have multiple <html> elements, something that isn't valid in an HTML document. Our updated stylesheet would look like this:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0">
  <xsl:output method="html"/>
        
  <xsl:template match="/">
    <html>
      <body>
        <xsl:apply-templates select="greetings/greeting"/>
      </body>
    </html>
  </xsl:template>
        
  <xsl:template match="greeting">
    <h1>
      <xsl:value-of select="."/>
    </h1>
  </xsl:template>
</xsl:stylesheet>

Notice that we had to modify our XPath expression; what was originally greeting is now greetings/greeting. As we develop stylesheets, we'll have to make sure our XPath expressions match the document structure. When you get unexpected results, or no results, an incorrect XPath expression is usually the cause.

As a final example, we could also write our stylesheet with only one xsl:template:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html"/>
        
  <xsl:template match="/">
    <html>
      <body>
        <h1>
          <xsl:value-of select="greeting"/>
        </h1>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Although this is the shortest of our sample stylesheets, our examples will tend to feature a number of short templates, each of which defines a simple transform for a few elements. This approach makes your stylesheets much easier to understand, maintain, and reuse. The more transformations you cram into each xsl:template, the more difficult it is to debug your stylesheets, and the more difficult it is to reuse the templates elsewhere.



Library Navigation Links

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