Traversing with XPath?

137 views Asked by At

I am looking for a faster way to grab contents with xpath.

I read this post:
Selecting a css class with xpath

put the first responses "class" selector in my project, as..

//*[contains(concat(" ", normalize-space(@class), " "), " attr-price ")]

which works great. It returns to me all the elements with the class "attr-price", and I can even do something like a compound selector by doing..

//*[contains(concat(" ", normalize-space(@class), " "), " attr-price second-class")]

However, the part of this I do not like is the //*. This makes XPath go through all nodes, and is decreasing my sites performance pretty significantly. I read on W3schools about the different types of selectors and have tried using / and // instead of //*, however none of these work. The attr-price elements are all within a <ul> would like to do something analagous to..

/ul/[contains(concat(" ", normalize-space(@class), " "), " attr-price ")]

this way I am hitting each of the UL's instead of every single element, and then searching for my class there, kind of like if I was using jQuery's

$('ul').find('.attr-price')

Any input is appreciated, thank you.

1

There are 1 answers

1
LarsH On BEST ANSWER

The XPath equivalent to

$('ul').find(...)

would be

//ul//...

So your XPath would become

//ul//*[contains(concat(" ", normalize-space(@class), " "), " attr-price ")]

Whether that is actually any faster depends on the XPath processor and the DOM model implementation, I guess.

On a different note, your compound selector

//*[contains(concat(" ", normalize-space(@class), " "),
       " attr-price second-class")]

will only work if the class attribute happens to contain both of those classes in the right order. If you want a compound selector that doesn't rely on the order in which the classes are listed (as it wouldn't in CSS), you'd need to use something like

//*[contains(concat(" ", normalize-space(@class), " "), " attr-price ")
 and contains(concat(" ", normalize-space(@class), " "), " second-class ")]

which is pretty clunky. Remember that if you have access to XPath 2.0, you can use tokenize() instead. For that, see https://stackoverflow.com/a/12165195/423105