How XSLT Template Rules Depend on Context
XSLT template rules cannot be relied on to fire in any particular order, each one is evaluated strictly in terms of the context established at that point. This context is strongly influenced both by the built-in XSLT template rules and by <xsl:apply-templates>
elements in template rules for higher-level nodes.
Initial Example
The initial example produces some stray data before the desired "Forecast for (Today...)" headings.
XML File (weather.xml)
Use the Sample XML Data File for XPath Context and Navigation and change the href
attribute to reference weather1.xsl.
XSLT File (weather1.xsl)
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40" > <xsl:template match="forecast"> <h2>Forecast for (Today <xsl:value-of select="@day"/>):</h2> <xsl:apply-templates/> </xsl:template> <xsl:template match="temperature"> <p><b>Temperature: <xsl:value-of select="."/>
<xsl:value-of select="@scale"/> </b></p> </xsl:template> <xsl:template match="humidity"> <p><b>Relative humidity: <xsl:value-of select="."/>% </b></p> </xsl:template> </xsl:stylesheet>
Formatted Output
The preceding style sheet appears to process three types of elements: <forecast>
, <temperature>
, and <humidity>
.
The built-in template rules for XSLT are also in effect—in particular, the built-in rule for the root and all element nodes, which looks like this if coded explicitly:
<xsl:template match="/|*" > <xsl:apply-templates /> </xsl:template>
By default, all element content is output to the result tree—not just the content of the three explicitly transformed elements.
Data items are shown before the heading when the <forecast>
template rule is evaluated, the context in which its match expression is evaluated is the context supplied by the default template rule. This works fine for processing the <forecast>
elements in the source document, and the corresponding template rules for the <temperature>
and <humidity>
children of the <forecast>
elements are then invoked by the <xsl:apply-templates/>
element.
But the context in the <temperature>
and <humidity>
templates' match
expressions are evaluated is not just the context supplied by the <forecast>
elements. There are other <temperature>
and <humidity>
elements in this document—the children of the <today>
element. The <today>
element's children are processed by any matching template rules.
Note The<wind>
and<precip>
elements' contents are passed to the result tree even though our style sheet does not include template rules for them. Again, this is a result of the built-in template rule for the root and element nodes.
You can control the XPath context which matched expressions are evaluated, by manipulating the context in two higher level template rules.
To change this document to display only the desired content from the <forecast>
elements' <temperature>
and <humidity>
, use the following step:
- Supply a specific template rule for the
<today>
element, suppressing its contents entirely; and - Supply specific child elements to be processed by the
<forecast>
element's<xsl:apply-templates>
element.
In Step 1, add the following template rule to the style sheet:
<xsl:template match="/weather/today" />
Note The empty template portion of this template rule. Nothing at all will be instantiated for the <today>
element in the source tree.
In Step 2, change the <forecast>
element's template rule, as follows:
<xsl:template match="forecast">
<h2>Forecast for (Today <xsl:value-of select="@day"/>):</h2>
<xsl:apply-templates select="temperature|humidity"
/>
</xsl:template>
Corrected Example
XML File (weather.xml)
Use the Sample XML Data File for XPath Context and Navigation and change the href
attribute to reference weathershort.xsl.
XSLT File (weathershort.xsl)
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/REC-html40" >
<xsl:template match="/weather/today" />
<xsl:template match="forecast">
<h2>Forecast for (Today <xsl:value-of select="@day"/>):</h2>
<xsl:apply-templates select="temperature|humidity"
/>
</xsl:template>
<xsl:template match="temperature">
<p><b>Temperature:
<xsl:value-of select="."/>
<xsl:value-of select="@scale"/>
</b></p>
</xsl:template>
<xsl:template match="humidity">
<p><b>Relative humidity:
<xsl:value-of select="."/>%
</b></p>
</xsl:template>
</xsl:stylesheet>
Formatted Output