Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A better way of selecting multiple elements by attribute name in XPath

Tags:

xpath

I'm looking to select a collection of elements based on an array of ID names. I'm currently using a giant OR statement essentially:

//*[@id='apple']|//*[@id='orange']|//*[@id='banana']

But building that string manually seems messy. Is there something like a nice SQL-esque "WHERE IN [a,b,c]" operator that I could be using?

I am using the HTTPAgilityPack for ASP.Net which I think equates to XPath1.o (feel free to correct me on that.)

Thanks.

like image 862
LesterDove Avatar asked Aug 26 '10 01:08

LesterDove


2 Answers

First, you could simplify this by using or. This avoids repeating the //* multiple times although you till specify the @id= part multiple times:

//*[@id='apple' or @id='orange' or @id='banana']

A more elegant solution is to check against a list of acceptable ids. Now if you're using XPath 1.x then you'll have to do a bit of gymnastics to get contains() to do your bidding. Specifically, notice that I've got spaces on both ends of the first string, and then concatenate spaces to each end of @id before looking for a match. This is to prevent an @id of "range" from matching, for example.

//*[contains(' apple orange banana ', concat(' ', @id, ' '))]

If you have are using XPath 2.0 then the way forward is simpler thanks to the addition of sequences to the language:

//*[exists(index-of(('apple', 'orange', 'banana'), @id))]
like image 113
John Kugelman Avatar answered Sep 30 '22 19:09

John Kugelman


Use:

//*[contains('|apple|banana|orange|', concat('|',@id, '|'))]

In case some of the id attributes may contain the "|" character, use another instead, that is known not to be present in the value of any of the id attributes.

An XPath 2.0 solution:

//*[@id=('apple', 'orange', 'banana')]

like image 21
Dimitre Novatchev Avatar answered Sep 30 '22 18:09

Dimitre Novatchev