Now that we're giddy with the excitement of having transformed an XML document, let's discuss the stylesheet and how it works. A big part of the XSLT learning curve is figuring out how stylesheets are processed. To make this clear, we'll go through the steps taken by the stylesheet processor to create the HTML document we want.
Before the XSLT processor can process your stylesheet, it has to read it. Conceptually, it doesn't matter how the XSLT processor stores the information from your stylesheet. For our purposes, we'll just assume that the XSLT processor can magically find anything it needs in our stylesheet. (If you really must know, Xalan uses an optimized table structure to represent the stylesheet; other processors may use that approach or something else.)
Our stylesheet contains three items: an <xsl:output> element that specifies HTML as the output format and two <xsl:template> elements that specify how parts of our XML document should be transformed.
Now that the XSLT processor has processed the stylesheet, it needs to read the document it's supposed to transform. The XSLT processor builds a tree view from the XML source. This tree view is what we'll keep in mind when we build our stylesheets.
Finally, we're ready to begin the actual work of transforming the XML document. The XSLT processor may set some properties based on your stylesheet (in the previous example, it would set its output method to HTML), then it begins processing as follows:
Do I have any nodes to process? The nodes to process are represented by something called the context. Initially the context is the root of the XML document, but it changes throughout the stylesheet. We'll talk about the context extensively in the next chapter. (Note: all XSLT processors enjoy being anthropomorphized, so I'll often refer to them this way.)
While any nodes are in the context, do the following:
Get the next node from the context. Do I have any <xsl:template>s that match it? (In our example, the next node is the root node, represented in XPath syntax by /.) There is a template that matches this node -- it's the one that begins <xsl:template match="/">.
If one or more <xsl:template>s match, pick the right one and process it. (The right one is the most specific template. For example, <xsl:template match="/html/body/h1/p"> is more specific than <xsl:template match="p">. See the discussion of the <xsl:template> element for more information.) If no <xsl:template>s match, the XSLT processor uses some built-in rules. See Section 2.4.5, "Built-in Template Rules" later in this chapter for more information.
Notice that this is a recursive processing model. We process the current node by finding the right xsl:template for it. That xsl:template may in turn invoke other xsl:templates, which invoke xsl:templates as well. This model takes some getting used to, but it is actually quite elegant once you're accustomed to it.
NOTE: If it helps, you can think of the root template (<xsl:template match="/">) as the main method in a C, C++, or Java program. No matter how much code you've written, everything starts in main. Similarly, no matter how many <xsl:template>s you've defined in your stylesheet, everything starts in <xsl:template match="/">.
Let's revisit our example and see how the XSLT processor transforms our document:
The XSLT stylesheet is parsed and converted into a tree structure.
The XML document is also parsed and converted into a tree structure. (Don't worry too much about what that tree looks like or how it works; for now, just assume that the XSLT processor knows everything that's in the XML document and the XSLT stylesheet. After the first two steps are done, when we describe various things using XSLT and XPath, the processor knows what we're talking about.)
The XSLT processor is now at the root of the XML document. This is the original context.
There is an xsl:template that matches the document root:
<xsl:template match="/"> <xsl:apply-templates select="greeting"/> </xsl:template>
A single forward slash (/) is an XPath expression that means "the root of the document."
Now the process begins again inside the xsl:template. Our only instruction here is to apply whatever xsl:templates might apply to any greeting elements in the current context. The current context inside this template is defined by the match attribute of the xsl:template element. This means the XSLT processor is looking for any greeting elements at the document root.
Because one greeting element is at the document root, the XSLT processor must deal with it. (If more than one element matches in the current context, the XSLT processor deals with each one in the order in which they appear in the document; this is known as document order.) Looking at the greeting element, the xsl:template that applies to it is the second xsl:template in our stylesheet:
<xsl:template match="greeting"> <html> <body> <h1> <xsl:value-of select="."/> </h1> </body> </html> </xsl:template>
Now we're in the xsl:template for the greeting element. The first three elements in this xsl:template (<html>, <body>, and <h1>) are HTML elements. Because they're not defined with a namespace declaration, the XSLT processor passes those HTML elements through to the output stream unaltered.
The middle of our xsl:template is an xsl:value-of element. This element writes the value of something to the output stream. In this case, we're using the XPath expression . (a single period) to indicate the current node. The XSLT processor looks at the current node (the greeting element we're currently processing) and outputs its text.
Because our stylesheet is an XML document (we're really harping on that, aren't we?), we have to end the <h1>, <body>, and <html> elements here. At this point, we're done with this template, so control returns to the template that invoked us.
Now we're back in the template for the root element. We've processed all the <greeting> elements, so we're finished with this template.
No more elements are in the current context (there is only one root element), so the XSLT processor is done.
Copyright © 2002 O'Reilly & Associates. All rights reserved.