tags:

views:

153

answers:

4

Consider this XML:

<people>
  <person>
    <firstName>Deane</firstName>
    <lastName>Barker</lastName>
  </person>
</people>

What if two XSLT templates match an element through different XPaths? I know that if the "match" element on two templates is identical (which should never happen, I don't think), the last template will fire.

However, consider this XSL:

<xsl:template match="person/firstName">
    Template #1
</xsl:template>

<xsl:template match="firstName">
    Template #2
</xsl:template>

The "firstName" element will match on either of these templates -- the first one as a child of "person" and the second one standalone.

I have tested this, and Template #1 executes, while Template #2 does not. What is the operative principle behind this? I can think of three things:

  1. Specificity of XPath (highly doubtful)
  2. Location in the XSLT file (also doubtful)
  3. Some pre-emption of Template #2 by Template #1. Something happens during the execution of Template #1 that tells Template #2 not to execute.
+4  A: 

Your first point is actually correct, there is a defined order described in http://www.w3.org/TR/xslt#conflict. According to the spec person/firstName has a priority of 0 while firstName has a priority of -0.5. You can also specify the priority yourself using the priority attribute on xsl:template.

Jörn Horstmann
Deane's second point is also relevant: if two templates match with the same specificity, it is strictly speaking an error, but most processors don't report the error and instead take the permitted option of applying the template that appears last in the stylesheet.
NickFitz
So, does this mean that one element will only ever have one template executed for it? My understanding is that the processor traverses the XML, and for each element asks, "Which template do I execute?" Is it correct that it will only ever execute a single template for each element in the XML?
Deane
Correction: person/firstName has a priority of 0.5, and firstName has a priority of 0. A pattern has the highest default priority (0.5) if and only if it has one or more slashes ('/') or square brackets ('[', ']')
Evan Lenz
Deane, to answer your question: "Does this mean that one element will only ever have one template executed for it?" The answer is "Yes, unless you use modes." Modes let you process the same node more than once, using a different template rule each time. See here for more: http://lenzconsulting.com/how-xslt-works/#modes
Evan Lenz
+2  A: 

I know that if the "match" element on two templates is identical (which should never happen, I don't think)

This can happen but would not be much point doing this and having two matching templates.

From the spec:

It is an error if this leaves more than one matching template rule. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the matching template rules that are left, the one that occurs last in the stylesheet.

So in other words you may get an error or it will just use the last template in your XSLT depending on how the processor your are using has been written to handle this situation.

Chris R
+1, Thanks for pulling this out of the spec.
Tomalak
A: 

Consider this with the context in mind. The first one matches, and changes the context n (so the second does not match). The context is set to AFTER the first one is selected and processed so the visible element from that context no longer contains "firstname". IF you want both to execute, then you can call them instead so that the context changes back to the top.

 <xsl:template match="people">
    <xsl:apply-templates select="person/firstname"/>
    <xsl:apply-templates select="firstname"/>
</xsl:template>
Mark Schultheiss
This is untrue. The XSLT processor decides which template to run by looking at the node it currently processes, and picking the most specific one by assessing the match expression and the template position and its inherent priority. How you call the template makes no difference at all - the `select` expression of `<xsl:apply-templates>` and the `match` pattern of `<xsl:template>` have no connection to each other whatsoever.
Tomalak
A: 

Note that the value of the match attribute is not an XPath expression (though it uses a subset of XPath syntax). It's an XSLT pattern. Absent explicit priority attributes, the choice comes down to which pattern has the highest default priority:

person/firstName has a default priority of .5

firstName has a default priority of 0

Thus, person/firstName wins.

A complete explanation of how conflict resolution works can be found here (although I recommend you study the entire chapter, "How XSLT Works"): Conflict Resolution for Template Rules

Evan Lenz