starman1979
starman1979

Reputation: 1064

XSLT matched template

I have a situation where I am trying to match a number of possible paths to a template in the following way:

<xsl:template match="blah">
  <xsl:apply-templates select="foo/*/baz" mode="someMode"/>
</xsl:template>

<xsl:template match="*" mode="someMode">
  <xsl:if test="current() != 'foo/bar/baz' and
                current() ! ='foo/bam/baz'">

    <!-- Process here --> 

  </xsl:if>
</xsl:template>

So as you can see, there can be any number of elements under 'foo' which have the 'baz' element (for example, 'bar', 'bam', 'bal', 'bav', etc.) but I know about only 2 of them, 'bar' and 'bam'. I don't want to process these ones, but the others I do. Unfortunately, the current() method is not returning the path that was matched, so the test always succeeds (even when the path is 'foo/bar/baz' or 'foo/bam/baz'.

How can I retrieve the path that was matched in the if-test?

Please note: I can't have other xsl:template elements that specifically match 'foo/bar/baz' and 'foo/bam/baz', as they are being processed in other places (in other ways).

Upvotes: 2

Views: 137

Answers (2)

C. M. Sperberg-McQueen
C. M. Sperberg-McQueen

Reputation: 25034

If you have other templates with mode="someMode" that match foo/bar/baz and foo/bam/baz, then your template that matches * in that mode will never fire on such elements, and the test in your conditional will always be true even if you re-formulate it to say what you want.

If you're not entirely sure that a given element that would have matched the pattern foo/bar/baz or foo/bam/baz is matched elsewhere and you want to make sure that the code inside your if statement won't fire for it, you can recast your test as

test="not(self::baz/parent::bar/parent::foo
          or self::baz/parent::bam/parent::foo)"

Many XSLT programmers would write it differently, though by adding that test in a predicate on the match pattern for the template:

<xsl:template mode="someMode" 
              match="*[not(self::baz/parent::bar/parent::foo
                      or self::baz/parent::bam/parent::foo)]">
  <!-- process ... -->
</xsl:template>

Upvotes: 0

Ian Roberts
Ian Roberts

Reputation: 122364

The current function doesn't return the path, it returns the current context node (i.e. outside of a [] predicate it's exactly the same as ., inside a predicate it's the value that . would be outside it).

Rather than using an <xsl:if> you should define no-op templates for the same someMode matching the specific elements you don't want, then the main * template will only fire for those you do want.

<xsl:template match="foo/bar/baz | foo/bam/baz" mode="someMode" />

<xsl:template match="*" mode="someMode">
  <!-- Process here -->
</xsl:template>

You say that

Please note: I can't have other xsl:template elements that specifically match 'foo/bar/baz' and 'foo/bam/baz', as they are being processed in other places (in other ways).

but this is the whole point of modes - existing foo/bar/baz templates for other modes will still do the same as they used to.

Upvotes: 2

Related Questions