tags:

views:

1848

answers:

4

I have several templates that match various nodes in an xml document. If I do just an
<xsl:apply-templates/> it somehow recursively outputs the text of all the nodes beneath. I just want it to recursively match any template I have defined. How do I do that ?

+1  A: 

Please post a small example of the behavior you are noticing. It is hard to debug this issue without something to work with.

In general, your code should look like the example here.

Again, if you post a code snippet it will be easier to help.

Yuval A
+1  A: 

Hi,

you could set a mode to apply only your own templates:

<xsl:template match="* | /" >
    <xsl:apply-templates mode="myMode" />
</xsl:template>

<xsl:template match="somenode" mode="myMode">
  <!-- do something here -->
</xsl:template>

Another option would be to overwrite the built-in template rules (see e.g. http://unix.com.ua/orelly/xml/xmlnut/ch08_07.htm)

0xA3
+6  A: 

This is happening because of the built-in templates in XSLT. XSLT has a couple of built in templates, which say:

  • when you apply templates to an element, process its child elements
  • when you apply templates to a text node, give its value

Together, it means that if you apply templates to an element but don't have an explicit template for that element, then its content gets processed and eventually you end up with the text that the element contains.

Read the full explanation here: http://www.dpawson.co.uk/xsl/sect2/defaultrule.html

You can override the default templates for text nodes by defining your own template and have it do nothing.

<xsl:template match="text()" />
Mads Hansen
+5  A: 

This is probably the most frequent problem even experienced XSLT programmers experience.

The observed behavior is exactly how an XSLT-compliant processor shoud behave.

Take into account that:

    <xsl:apply-templates/>

is an abbreviation for:

    <xsl:apply-templates select="child::node()"/>

and the existence of the built-in template rules. According to the XSLT 1.0 Spec.:

"5.8 Built-in Template Rules

There is a built-in template rule to allow recursive processing to continue in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule:

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

There is also a built-in template rule for each mode, which allows recursive processing to continue in the same mode in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule for mode m.

<xsl:template match="*|/" mode="m">
  <xsl:apply-templates mode="m"/>
</xsl:template>
There is also a built-in template rule for text and attribute nodes that copies text through:
<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

The built-in template rule for processing instructions and comments is to do nothing.

<xsl:template match="processing-instruction()|comment()"/>

The built-in template rule for namespace nodes is also to do nothing. There is no pattern that can match a namespace node; so, the built-in template rule is the only template rule that is applied for namespace nodes.

The built-in template rules are treated as if they were imported implicitly before the stylesheet and so have lower import precedence than all other template rules. Thus, the author can override a built-in template rule by including an explicit template rule "

--- End of XSLT Spec quote ---

So, if the author wants to be in full control of the XSLT processing, they should override all built-in templates.

For example, if we do not want text() nodes to be copied to the output, we can cause them to be ignored by overriding the built-in template in the following way:

    <xsl:template match="text()" />

Dimitre Novatchev