22

I would like to know if there is shorter approach to selecting a list of nodes ignoring the ones that have an attribute value specified in a list

Working example:

/item[not(@uid='id1') and not(@uid='id2')]

Desired alternative:

/item[not(@uid in('id1','id2'))]
Aitorito
  • 235
  • 1
  • 2
  • 5

4 Answers4

26

You can either use regex - if your xpath implementation supports it - or write

/item[not(@uid='id1' or @uid='id2')]

which might be a bit shorter.

Arne
  • 2,106
  • 12
  • 9
  • 1
    You were right, the other method if i had two items like 'id1' and 'id11' it would ignore both by error – Aitorito Jul 16 '12 at 08:56
7

If the list of attribute names is very long, the following is a good way to handle this situation:

//item[not(contains('|attr1|attr2|attr3|attr4|attr5|attr6|attrN|', 
                    concat('|', @uid, '|')
                    )
           )]
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • I needed to build very long XPath in .NET. Instead of using stuff like LINQ Aggregate method with seed, you can just simply join strings with '|', add trailing and leading, and use it. Thanks! – Nickmaovich Mar 06 '14 at 11:50
4

Maybe something like this??

/item[not(contains('id1 id2', @uid))]
VSP
  • 2,367
  • 8
  • 38
  • 59
  • 1
    works, but risky for changes, as `contains(x, y)` is true for non-existing y. – Arne Jul 16 '12 at 07:50
  • 1
    @Arne This one is the shortest but in what cases would it fail? The attribute we use to filter is a unique id without spaces – Aitorito Jul 16 '12 at 07:56
0

At least in Xpath 2 general comparisons on sequences are performed pairwise and existentially, so you can write:

/item[not(@uid = ('id1','id2'))]
BeniBela
  • 16,412
  • 4
  • 45
  • 52