Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath - Difference between 'not' and '!='

Tags:

xpath

Just a quick question as to the difference between xpath's 'not' and '!=' in the following content.

Taking the XML:

<years>
  <year value="2010"></year>
  <year value="2010"></year>
  <year value="2010"></year>
  <year value="2009"></year>
</years>

I want to select unique years. I have struggled for a while to achieve this, but managed in the end, but in a curious way that I did not expect.

The following xpath is correct for my intention and returns two unique year nodes of 2009 and 2010.

years/year[not(@value = preceding-sibling::year/@value)]

The following only returns the 2009 year node.

years/year[@value != preceding-sibling::year/@value]

The only difference between them is the != and not operators. I've pondered on this a while and I can't find a difference that I could satisfactorily explain to anyone else.

Perhaps someone could help.

Cheers

Steve

like image 591
Steven Wilber Avatar asked Feb 16 '10 15:02

Steven Wilber


People also ask

What is the difference between '/' and in XPath?

Difference between “/” and “//” in XPathSingle slash is used to create absolute XPath whereas Double slash is used to create relative XPath. 2. Single slash selects an element from the root node. For example, /html will select the root HTML element.

What does /* mean in XPath?

/* selects the root element, regardless of name. ./* or * selects all child elements of the context node, regardless of name.

Why do we use * in XPath?

The '*' is used for selecting all the element nodes descending from the current node with @id-attribute-value equal to 'Passwd'.

What is the difference between DOT and text in XPath?

enter image description here The XPath text() function locates elements within a text node while dot (.) locate elements inside or outside a text node.


2 Answers

The second example does not work because if you apply it to each of the first 3 nodes, it never matches. For the first <year>, there's no preceding sibling whose value one might try to compare to, so it fails to match. For the second and third, their preceding node does have the same value, so the non-equality test fails and leads to no match again.

The not(...) version works because in the first node, the whole @value = preceding-sibling::year/@value fails due to the lack of a preceding sibling, and this failure in inverted by not, giving you a match on the first node.

like image 110
Max Shawabkeh Avatar answered Oct 16 '22 12:10

Max Shawabkeh


In XPath, a != b and not(a = b) are VERY different

Here's why

From the spec for XPath 1.0:

If both objects to be compared are node-sets, then the comparison will be true if and only if there is a node in the first node-set and a node in the second node-set such that the result of performing the comparison on the string-values of the two nodes is true.

that means that (a = b) for node sets is true if there is a match between any element in a and b.
(a != b) means that some element in a DOES NOT match some element in b. so for the node sets A = (1, 2), B = (1, 2). BOTH a = b and a != b will return true.

In your case what's happening is that (2010 != empty set) is always false, while
not (2010 = empty set) is always true. Think about the matching rules as above.

like image 30
Kyle Butt Avatar answered Oct 16 '22 12:10

Kyle Butt