XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Dirty XSLT Output

Dirty XSLT Output

September 25, 2002

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

Next Pagearrow