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.
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.
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.
Our first template matches "/", the XPath expression for the document's root element.
<xsl:template match="/"> <xsl:apply-templates select="greeting"/> </xsl:template>
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>
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.
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.
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>
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>
This template does nothing.
<xsl:template match="comment()|processing-instruction()"/>
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:
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"/>
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.
Copyright © 2002 O'Reilly & Associates. All rights reserved.