Dirty XSLT Output
by John E. Simpson
|
Pages: 1, 2
So now let's trace the logic of your Transformation #2:
- First template rule:
- Match on any
worldelements in the source tree. - If you get a match, instantiate in the result tree the basic structure
of an XHTML document:
html,head, and so on, down through atableelement. - Within the result tree's
tableelement, process all template rules for thecountrychild elements of thisworldelement.
- Match on any
- Second template rule:
- Match on any
governmentelement which is a child of acountryelement. (Note that this does not correspond to the instruction provided by the first template rule'sxsl:apply-templateselement.) - If you get such a match, instantiate in the result tree a
trtable-row element, within which will be a singletdelement and the string-value of the context node's (that is, thecountryelement's)executive_branch/chief_of_state"grandchild."
- Match on any
That looks fine so far. The problem is that your source tree includes a
handful of elements (and in one case, a text node) for which there are no
explicit template rules. For all these cases
-- including the country element which you expressly
said (via that xsl:apply-templates) you wanted to be
processed -- the built-in template rules are automatically
applied. For every one of the elements, therefore -- every one,
that is, except world (covered by Transformation
#2's first template rule) and the government child(ren) of
country elements (from Transformation #2's second template rule)
-- every child of that element is processed as if you'd
explicitly coded the built-in template rule. This includes the
text-node child of the nameelement --
that is, the string "United States of America." This text node
gets transferred to the result tree, unchanged, at the point
where the name element would normally be processed.
So that's why "United States of America" shows up in
Transformation #2's result tree where it does.
But what about Transformation #1? Why isn't the name
element (with the same text node child) processed there, too?
Let's trace its logic:
- First template rule: same as for Transformation #2.
- Second template rule:
- Match on any
countryelement. (Note that this does correspond, exactly, to the instruction provided by the first template rule'sxsl:apply-templateselement.) - If you get such a match, instantiate in the result tree a
trtable-row element, within which will be a singletdelement and the string-value of the context node's (that is, thecountryelement's)government/executive_branch/chief_of_state"great-grandchild."
- Match on any
Why, then, isn't the country element's name
descendant processed? Because Transformation #1 overrides, for all
country elements, the built-in template rule for elements in
general: no children, and hence no descendants, of country
will be processed at all by further template rules (built-in or
otherwise). If you'd like Transformation #1 to duplicate the results of
Transformation #2, just modify its second template rule as follows:
<xsl:template match="country">
<xsl:apply-templates
select="appellative"/>
<tr>
<td>
<xsl:value-of
select="government/executive_branch/chief_of_state"/>
</td>
</tr>
</xsl:template>
Since there's no explicit template rule provided for processing
appellative elements, the built-in rules take effect --
trickling all the way down to the text node, "United States of America,"
which is a child of the name element.
By the way, I often find these built-in template rules (especially the one for text nodes) mildly distracting, especially when debugging a stylesheet. If you're distracted by them, too, feel free to override them with empty explicit template rules of your own. For instance:
<!-- Suppress all text nodes by default
-->
<xsl:template match="text()" />
Not everyone agrees with this approach, but it puts more explicit control in the hands of the stylesheet developer. And when I'm developing a stylesheet, that's where I prefer the control to be.
Correction: grouping with XSLT
|
Also in XML Q&A | |
In the July XML
Q&A column, I discussed using the generate-id()
function, in concert with the key() and
current() functions, to group source-tree data. Shortly after
that column appeared, I received a nice message from Geert Josten. He used
the examples from that column to help test an "XSLT parser" he'd built
using the, as he put it, "very unknown programming language called
MetaMorphosis (www.ovidius.com)."
Josten said he'd fixed a couple of small problems involving use of the
current() and generate-id() functions. But then
he went on to point out some flaws in my explanation of how the
generate-id() function works.
In particular, the column said, "whatever algorithm it uses [for generating IDs, an XSLT processor must generate the same key value for any given 'seed value' (such as a node's string-value) in a given processing instance." But this statement implies that a node's string-value is alone sufficient for generating a unique ID; in fact, if this were true, two attributes (for example) with the same value would have the same ID. This clearly isn't the case.
Thanks to Geert Josten for pointing out the error.
- More about xslt please
2002-10-14 20:39:29 sean Ginter