zakmck
zakmck

Reputation: 3024

Strange XSL matching behaviour

There is something about XSL matching rules I cannot get.

I've this input:

<root>
  <metadata>
  </metadata>
  <elements>
    <a-elems>
          <a>A1</a>
          <a>A2</a>
    </a-elems>
    <b-elems>
      <b>B1</b>
      <b>B2</b>
    </b-elems>
  </elements>
</root>

This XSL works as I want, a list of <a> values is reported:

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:template match = "/">
        _____ Elements _____
        <xsl:apply-templates select = "root/elements/*/*" />
    </xsl:template>


  <xsl:template match = "a-elems/a">
    __ A ELEM: <xsl:value-of select = "."></xsl:value-of> __
  </xsl:template>

  <xsl:template match="*">
        <xsl:message>Excluding <xsl:value-of select = "name(.)" /></xsl:message>
  </xsl:template>

</xsl:stylesheet>

However, I think this root template, where I state the level I want to start from, would be cleaner:

<xsl:template match = "/root/elements">
    _____ Elements _____
    <xsl:apply-templates select = "*/*" />
</xsl:template>

But it doesn't work, I get the 'Excluding root' message and I understand the template never matches. I don't get why, I've also tried select = "*" and adding priority attributes.

Upvotes: 0

Views: 26

Answers (1)

Tim C
Tim C

Reputation: 70648

XSLT will start off by looking for a template that matches / (the document node). By changing the template that matches / to /root/elements will result in XSLT using it's built-in template rule for matching / instead. This built-in template is effectively this:

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

The xsl:apply-templates will select the child root node. This will then be matched by the template matching * and so you get your message, and no more process is done.

The easiest solution would be to go back to what you had.

EDIT: In answer to your comment, you don't always have to redefine the /. Another slight variation of your original solution would be to do this...

<xsl:template match = "root">
    _____ Elements _____
    <xsl:apply-templates select = "elements/*/*" />
</xsl:template>

Upvotes: 1

Related Questions