
Dirty XSLT Output
Why am I getting dirty output?
I have observed "dirty output" applying different template rules that look equivalent to me. The source document is:
<world>
<country>
<appellative>
<name>United States of
America</name>
</appellative>
<government>
<executive_branch>
<chief_of_state>
<name>George W.</name>
<surname>Bush</surname>
</chief_of_state>
</executive_branch>
</government>
</country>
</world>
I'm looking for this (partial) result:
...
<table border="1">
<tr>
<td>George W. Bush</td>
</tr>
</table>
...
I can get this result using the following transformation (call it Transformation #1):
<xsl:template match="world">
<html>
<head>
<title>world</title>
</head>
<body>
<table border="1">
<xsl:apply-templates
select="country"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="country">
<tr>
<td>
<xsl:value-of
select="government/executive_branch/chief_of_state"/>
</td>
</tr>
</xsl:template>
I've also tried this transformation (call it Transformation #2; compare the boldfaced portions with their counterparts above):
<xsl:template match="world">
<html>
<head>
<title>world</title>
</head>
<body>
<table border="1">
<xsl:apply-templates
select="country"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="country/government">
<tr>
<td>
<xsl:value-of
select="executive_branch/chief_of_state"/>
</td>
</tr>
</xsl:template>
What I actually get from the latter, though, is this:
...
<table border="1">United States of America
<tr>
<td>George W. Bush</td>
</tr>
...
Why, in this case, does "United States of America" come out? I think
the problem is in the xsl:apply-templates element, but I do
not understand why. Can you help me?
A: You're on the right track; the problem is indeed related to the
xsl:apply-templates element. More exactly, it's attributable
to the cumulative effect of that element together with the explicit
or implicit template rules elsewhere in the stylesheet.
By "explicit" template rules, I mean the template rules --
xsl:template elements and their descendants -- which you've
expressly coded in your stylesheet. In Transformation #1, notice that
there's a direct correspondence between the value of the
xsl:apply-templates element's select attribute
(whose value is "country") and the match attribute of an
xsl:template rule.
In your Transformation #2, though, there is no such direct
correspondence. While the select attribute still has the
value "country," there are no match attributes with this
value; the only other template rule matches on "country/government"
instead. What you've run afoul of here is not the template rules you've
explicitly coded, but the built-in template rules established by
the XSLT 1.0
Recommendation. These are the "implicit" template rules.
Built-in template rules are defined for the root node, elements, text, attributes, comments, and processing instructions (PIs). The two built-ins causing the mysterious-seeming discrepancy in Transformation #2 are those for element and text nodes:
<!-- Element nodes with no explicit
template rule -->
<xsl:template match="*">
<xsl:apply-templates />
</xsl:template>
<!-- Text nodes with no explicit template rule
-->
<xsl:template match="text()">
<xsl:value-of select="." />
</xsl:template>
The built-in template rule for element nodes says, "Process all template rules -- including built-in ones, if necessary -- for all children of the context element node." Note that the term "children" covers not only child elements, but also child text, comment, and PI nodes. For a given text node, the built-in template rule simply transfers the string-value of the text node straight to the result tree. In both cases, as with the other built-in template rules, the built-ins are automatically processed by the XSLT processor just as if you'd explicitly coded them in your stylesheet -- unless you explicitly override them, or provide some other constraint which keeps them from kicking in.
Pages: 1, 2 |