Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select alternative subpaths in xpath

Tags:

xpath

This works:

(//someparentpath/h3 | //someparentpath/ul/li/div)/somechildpath

This does not :( Why?

//someparentpath/(h3 | ul/li/div)/somechildpath
like image 215
Marina Avatar asked Feb 13 '14 04:02

Marina


2 Answers

Good question, I'm interested in the "why" myself.

As a practical matter, though, you can rewrite this

//someparentpath/(h3 | ul/li/div)/somechildpath

as this (not quite equivalent)

//someparentpath//*[self::h3 or self::ul/li/div]/somechildpath

Which is not too much worse.

But yeah, I've been frustrated by that.

like image 110
harpo Avatar answered Oct 22 '22 13:10

harpo


XPath 1.0's grammar does not allow alternations in axis steps, see the specifications for node sets or try the XPath 1.0 Grammar Test Page. Your first query is allowed by the grammar, the second is no valid XPath 1.0.

If you've got any chance, switch to an XPath 2.0 implementation which offers much more possibilities in querying XML. Both of your queries are valid XPath 2.0 statements.

In XPath 1.0, you will have to either:

  • Completely write out the path two times and use the union of those:

    //someparentpath/h3/somechildpath | //someparentpath/ul/li/div/somechildpath
    

    or the allowed query with common axis steps in the end, which is at least a little bit less repeating:

    (//someparentpath/h3 | //someparentpath/ul/li/div)/somechildpath
    
  • Use some descending-or-self-hack with predicates like proposed by harpo and JLRishe, but they have both in common that you might match more elements than you want to.

like image 27
Jens Erat Avatar answered Oct 22 '22 13:10

Jens Erat