|Chapter 4 - Templates Rule!|
|XSLT For Dummies|
|by Richard Wagner|
|Hungry Minds 2002|
Within a template rules template, a few key XSLT instructions do the yeomans work of generating nodes for the result documents. These action instructions you use most often are xsl:apply-templates , xsl:copy , xsl:copy-of , and xsl:value-of .
Tip In XSLTSpeak, top-level XSLT elements, such as xsl:template or xsl:output are called elements, whereas XSLT elements in the template rule that are used to create part of the result tree are called instructions .
The xsl:apply-templates element is perhaps the most commonly used instruction inside template rules. Its most basic syntax is:
<xsl:apply-templates select="expression" />
The select attribute (shown in italic) is purely optional.
Tip Think of xsl:apply-templates as something like a stereotypical factory supervisor. It doesnt really do anything by itself, but is charged with telling others, "Hey you, do this."
The purpose of xsl:apply-templates is to invoke the template rule most appropriate for the current node and its children. It doesnt really do anything by itself, but tells another template rule to do something. In some cases, the template rule called upon is the one that contains the xsl:apply-templates instruction. In other cases, it may be another template rule defined in your stylesheet. And, if nothing else is found, the XSLT processor applies one of XSLTs built-in template rules. (I discuss built-in template rules later in the chapter.)
Two obvious questions follow: How does xsl:apply-templates know which nodes to process? And after a node or node set is selected for processing, how does xsl:apply-templates decide which template rule to apply? I discuss the answers to these questions in the next two sections.
Scope of xsl:apply-templates
The xsl:apply-templates instruction processes nodes within its context or scope. When its select attribute is not defined, then its scope is the node set returned from the match pattern of the template rule it is inside of. For example, in the code snippet below, xsl:apply-templates processes the tv element and its children from the XML file shown in Listing 4-2:
<xsl:template match="tv"> <xsl:apply-templates> </xsl:template>
For each node in the node set, its template rule is applied along with all of its childrens template rules.
Or, if select is defined, only the nodes that result from the expression are transformed, along with their children. For example, when the following template rule is processed on the tv.xml file in Listing 4-2, only the aspectratio element is applied by xsl:apply-templates , the tv , model , and type elements are ignored by this xsl:apply-templates instruction:
<xsl:template match="tv"> <xsl:apply-templates select="aspectratio"> </xsl:template>
Looking for the best template rule
For each node that is processed by xsl:apply-templates , the XSLT processor looks for the best template rule to apply to it.
If the instructions select attribute is defined, the processor will look for the most appropriate template rule for that node. But if select isnt defined, the template rule that contains xsl:apply-templates is chosen for the current node.
However, in both of these cases, dont forget about the children. The current nodes children are also processed, so the XSLT processing engine goes through the same process of looking for the most appropriate template rule for each child. If a template rule is found matching that node, it will then be processed. But if not, then a built-in template rule is processed instead.
Heres a summary of the behavior of xsl:apply-templates :
Remember In addition to elements, xsl:apply-templates also applies text nodes that are children of the current node.
Consider a few examples to get a better grasp of its intended actions. I use the following XML fragment in Listing 4-3 as the source document in each of these.
Listing 4-3: miniscore.xml
<!-- miniscore.xml --> <score id="1"> <film>A Little Princess</film> <composer>Patrick Doyle</composer> <year>1995</year> <grade>100</grade> </score>
Using xsl:apply-templates on the score element, the template rule is defined as:
<xsl:template match="score"> <xsl:apply-templates/> </xsl:template>
This template rule processes the score node and its children (using built-in templates, which I discuss later in the chapter) to send their content (in other words, text nodes) to the result tree. Because the score element has no text content, no text is added to the result tree. But, because the score element has four child elements that have text nodes, the child elements content is transferred to the result document:
A Little Princess Patrick Doyle 1995 100
Using xsl:apply-templates with a select attribute, the template rule supplied is defined as follows :
<xsl:template match="score"> <xsl:apply-templates select="grade"/> is the critic's rating for the musical score of <xsl:apply- templates select="film"/> </xsl:template>
In this template rule, I apply the template specifically on the grade and film elements to add their content to the result tree. In between these two, I add literal text to the output. The result is:
100 is the critic's rating for the musical score of A Little Princess
The other children of the score element ( composer and year ) were not added to the result tree, because the xsl:apply-templates s select attribute didnt match these elements.
If you use xsl:apply-templates on an element with no children, only that particular element is processed:
<xsl:template match="film"> <movie><xsl:apply-templates/></movie> </xsl:template>
The preceding template sends the following text to the result tree:
<movie>A Little Princess</movie>
You can use the xsl:copy element to do just what youd expect with a name like thatthis element copies the current node. It has a basic syntax of:
However, keep in mind some specific behaviors to this xsl:copy instruction:
To illustrate , I use the miniscore.xml file (refer to Listing 4-3) as my source document. Using an empty xsl:copy element when the composer element is the match pattern, the code is defined as:
<xsl:template match="composer"> <xsl:copy/> </xsl:template>
The literal result of this template is <composer></composer> , but the XSLT processor shortens the empty tag to:
As you can see, the primary purpose of xsl:copy is to carry over the element tags. However, if you combine it with xsl:apply-templates , you copy both the tags and its content:
<xsl:template match="composer"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template>
This template outputs:
When you use xsl:copy and xsl:apply-templates on a current node that has children, the template rule copies the current nodes tags and the content of the children. For example:
<xsl:template match="score"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template>
<score> A Little Princess Patrick Doyle 1995 100 </score>
xsl:copy-of may be similar in name to xsl:copy , but its behavior is quite distinct. It has a basic syntax of:
While xsl:copy provides a carbon copy of some parts of the returned node set, xsl:copy-of does moreit duplicates everything inside the current node. Specifically, xsl:copy-of :
To copy the score element from the miniscore.xml (refer to Listing 4-3) to a new result document, I set up a new template rule. The template rule for copying the score element as is from the source tree to the result tree is defined as:
<xsl:template match="score"> <xsl:copy-of select="."/> </xsl:template>
The template rules match pattern returns a score element, and the . expression inside the select attribute of the xsl:copy-to returns the current node (and all its children), producing the following output:
<score id="1"> <film>A Little Princess</film> <composer>Patrick Doyle</composer> <year>1995</year> <grade>100</grade> </score>
The select attribute of the xsl:copy-of element determines what is copied to the result tree. Suppose you define a more limited template rule:
<xsl:template match="score"> <xsl:copy-of select="year"/> </xsl:template>
This template rule results in a literal copy of only the year element (both tags and content):
The xsl:value-of instruction is used when you want to convert part of the XML source to a string (plain text). It has a basic syntax of:
This instruction wants nothing to do with producing XML tags, so you never get elements or attributes when you use it. Specifically, the xsl:value-of element has the following behavior:
Using the miniscore.xml file in Listing 4-3 as the source, if I use xsl:value-of on a single element ( film ), the template rule looks like:
<xsl:template match="score"> <xsl:value-of select="film"/> </xsl:template>
The film element is converted to text:
A Little Princess
xsl:value-of can also be used to convert an attribute to a string. For example, if I use a special @ character in the select attribute to denote an attribute:
<xsl:template match="score"> <xsl:value-of select="@id"/> </xsl:template>
It returns the following output:
Table 4-2 summarizes the behavior of xsl:copy , xsl:copy-of , and xsl:value-of .
Remember A common mistake many XSLT stylesheet authors make is using a match attribute in place of the select attribute in an xsl:copy-of , xsl: apply-templates , or xsl:value-of instruction. Youll get a processing error if this occurs in your stylesheet.