KennyBOT
KennyBOT

Reputation: 447

Why is a better matched template not chosen?

I have the following xml:

<root xmlns:s="http://example.com/schema">
  <foo>
     <s:bars>
       <s:bar name="normal">bar101</s:bar>
       <s:bar name="special">Foobar</s:bar>
       <s:bar name="super">FuBar</s:bar>
     </s:bars>
  </foo>
</root>

I use the following xslt template to output the bar elements:

  <xsl:template match="root">
    <foos>
      <xsl:apply-templates select="foo/s:bars"/>
    </foos>
  </xsl:template>

  <xsl:template match="s:bars/s:bar[@name='special' or @name='super']">
    <xsl:element name="{@name}">
      <xsl:text>special value:</xsl:text>
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="s:bars/s:bar">
    <xsl:element name="{@name}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>

Strangely enough this outputs the following xml when using the .Net XSLT processor:

<foos>
  <normal>bar101</normal>
  <special>Foobar</special>
  <super>FuBar</super>
</foos>

Apparently the template for s:bars/s:bar[@name='special' or @name='super'] is not used. I expected the following output:

<foos>
  <normal>bar101</normal>
  <special>special value:Foobar</special>
  <super>special value:FuBar</super>
</foos>

I tried adding an extra template to select bars

  <xsl:template match="s:bars">
    <xsl:comment>bars</xsl:comment>
    <xsl:apply-templates />
  </xsl:template>

but that didn't change the result (but did add <!--bars--> to the result so the template gets called.)

I seem to expect something different from the template rules or misunderstand them. Shouldn't a match on an element AND attributes be selected over a match on ONLY an element?

How should I change my XSLT template to get my desired output with the .Net XSLT processor implementation?

Upvotes: 3

Views: 352

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167781

Both templates have the same priority 0.5 (see http://www.w3.org/TR/xslt#conflict) so the XSLT processor can either report an error or take the last one. If you don't get an error then your XSLT processor has taken the last matching template rule. So either change the order or set an explicit priority (e.g. <xsl:template match="s:bars/s:bar[@name='special' or @name='super']" priority="5">) on the one you want to be preferred.

Upvotes: 2

Related Questions