23

I would like how to use the "not" in XPath properly. I just can't seem to get it to work with attributes.

Say I have this expression: //*[@name = 'Bob'] It is valid, and will return all nodes that have a name attribute equaling 'Bob'.

Now if I want all nodes that have a name attribute that do not equal 'Bob', I need to use an XPath such as: //*[@name not(='Bob')] but this is invalid.

I have tried multiple combinations with not() being placed in a different order, but I can't seem to get this to work. Could someone please inform me how to use not() properly?

Also, does the order change when using elements instead of attributes? Such as: //name[text() = 'Bob']

Thanks! :)

developer
  • 7,252
  • 14
  • 49
  • 57

3 Answers3

27

According to : http://msdn.microsoft.com/en-us/library/ms256086.aspx, have you tried

//*[@name != 'Bob']
mathieu
  • 30,974
  • 4
  • 64
  • 90
  • 4
    @mathieu: I would be better to quote the specs (not MS documentation), from http://www.w3.org/TR/xpath/#booleans *"If one object to be compared is a node-set and the other is a string, then the comparison will be true if and only if there is a node in the node-set such that the result of performing the comparison on the string-value of the node and the other string is true"* –  Aug 05 '10 at 20:10
  • 1
    @mathieu: This method works for numerical values but not for string values. //*[@numerical != 1] works. //*[@string != "someString"] does not. Only the root element is being returned! – developer Aug 05 '10 at 21:20
  • 1
    @Alejandro: I did, but it only works for numerical values, not string values like I mentioned above. With the string value, the only result I get is the root node. – developer Aug 06 '10 at 14:57
  • @iHeartGreek: This works. Other order comparison operators (like >) only works for numbers (in XPath 2.0 you could use `op:gt` that works with collations). –  Aug 06 '10 at 15:45
  • @Alejandro: I don't know what the problem could be then.. it doesn't work in the implementation I have. What could be possible sources of the problem? – developer Aug 06 '10 at 16:45
  • @iHeartGreek: Ask other question with input sample, desired output and in progress stylesheet, and someone could answer that to you. Meanwhile, you should mark this as answer, I think. –  Aug 06 '10 at 17:06
  • @Alejandro: ok, I selected it as the answer. I will try to ask another question next week. – developer Aug 06 '10 at 19:39
  • @Alejandro: I think there is an issue with my XSL code, but it only became apparent to me once I used !=. I did some further testing, and found the searches do not go through entire hierarchy. I posted a question as I still can't fix it. http://stackoverflow.com/questions/3451325/xpath-results-from-xslt-are-incorrect-not-going-through-entire-xml – developer Aug 10 '10 at 16:48
8

Try

 //*[@name != 'Bob']

or

  //*[not(@name = 'Bob')]

should work both.

Doc Brown
  • 19,739
  • 7
  • 52
  • 88
  • This method works for numerical values but not for string values. //*[@numerical != 1] works. //*[@string != "someString"] does not. Only the root element is being returned! – developer Aug 05 '10 at 21:19
  • I am pretty sure that this will work for strings. Sure you did not make an error, for example, wrong case? The comparison is case-sensitive. – Doc Brown Aug 06 '10 at 14:24
  • yes I tried various searches. I am only getting the root node returned. :S – developer Aug 06 '10 at 14:57
  • Please post a complete example, a small XML file and the XPATH you are really trying, then we shall see further. – Doc Brown Aug 06 '10 at 16:08
  • I think there is an issue with my XSL code, but it only became apparent to me once I used !=. I did some further testing, and found the searches do not go through entire hierarchy. I posted a new question as I still can't fix it. http://stackoverflow.com/questions/3451325/xpath-results-from-xslt-are-incorrect-not-going-through-entire-xml – developer Aug 10 '10 at 16:49
  • Note that `//*[not(@name='Bob')]` will also match elements without a name attribute: since the `@name` node-set will be empty, `@name='Bob'` will be trivially false, and `not(@name='Bob')` will be trivially true. – outis Dec 29 '13 at 11:34
  • Thanks for this suggestion. For some reason != wasn't working, but not() does. I was trying to hide the header row in a table with a certain class. The former returned no rows at all, the latter returned the non-header rows. – lvanzyl Dec 17 '15 at 19:49
6
//*[@name and @name != 'Bob']
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 1
    Doesn't this give all elements whether they have @name or not? I need it to be an element with @name and then have it not equal 'Bob' – developer Aug 05 '10 at 19:52
  • I think just //*[@name != 'Bob'] would work.. as others suggested. BUT This method works for numerical values but not for string values. //*[@numerical != 1] works. //*[@string != "someString"] does not. Only the root element is being returned! – developer Aug 05 '10 at 21:19
  • Sorry, it is my understanding that your solution does in fact work. I think there is an issue with my XSL code, but it only became apparent to me once I used !=. I did some further testing, and found the searches do not go through entire hierarchy. I posted a new question as I still can't fix it. http://stackoverflow.com/questions/3451325/xpath-results-from-xslt-are-incorrect-not-going-through-entire-xml – developer Aug 10 '10 at 16:51