yegor256
yegor256

Reputation: 105043

How to find all not matching elements in XPath expression of XSL template?

This is my XML:

<f>
  <a>10</a>
  <a>2</a>
  <a>4</a>
  <a>13</a>
  <b>55</b>
  <b>4</b>
</f>

I'm trying to match elements <b/> which are not equal to <a/>:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:template match="b[. != //a]">
    <xsl:text>found!</xsl:text>
  </xsl:template>
</xsl:stylesheet>

However, it doesn't work. I believe, my expression . != //a is wrong, since //a matches only the first occurrence of <a/>. What is the right expression?

It's a test sample, please don't suggest other possible ways of solving this task. I only need a fix to the XPath expression.

Upvotes: 0

Views: 245

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

The smart (and efficient) way to do this is to use a key:

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

<xsl:key name="a" match="a" use="." />

<!-- other templates -->

<xsl:template match="b[not(key('a', .))]">
    <!-- do something -->
</xsl:template>

</xsl:stylesheet>

To further clarify the reason why your attempt did not work is that you are comparing sequences. This comparison is defined to return true

if there is a pair of atomic values, one in the first operand sequence and the other in the second operand sequence, that have the required magnitude relationship.

IOW, your expression b[. != //a] returns true for any b that is unequal to at least one a - which in your example means for all of them.

Upvotes: 2

Martin Honnen
Martin Honnen

Reputation: 167426

Most XPath users using e.g. . != $sequence want rather not(. = $sequence) e.g. not(. = //a) i.e. the current . item is not equal to any a element.

Upvotes: 2

Related Questions