How to choose alternate subpaths in xpath

It works:

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

This is not :( Why?

 //someparentpath/(h3 | ul/li/div)/somechildpath 
+6
source share
3 answers

Grammar XPath 1.0 does not allow you to alternate axis steps; see specifications for node sets or try the XPath 1.0 Grammar Testing Page . Your first query is resolved by grammar, the second is not valid XPath 1.0.

If you have a chance, switch to an XPath 2.0 implementation that offers much more options when querying XML. Both of your queries are valid XPath 2.0 statements.

In XPath 1.0, you need to either:

  • Write the path completely twice and use the union of them:

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

    or an allowed request with common steps at the end that at least repeats a little less:

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

+6
source

I think closest you can get the following:

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

However, as already mentioned in harpo, // does not allow them to be exactly equivalent, and I don’t think there is a way around this in one expression. Note: if you are working in XSLT, you can use several variable assignments to achieve what you are trying to do and avoid some of the redundancy:

 <xsl:variable name="ppath" select="//someparentpath" /> <xsl:variable name="children" select="($ppath/h3 | $ppath/ul/div/li)/somechildpath" /> 

Note that the hypothetical expression you described is:

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

Permitted in XPath 2.0. This is simply not allowed in XPath 1.0 because 1.0 does not allow you to have expressions partially through the path.

+3
source

Good question, I'm wondering why.

As a practical question, you can rewrite this

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

like this (not quite equivalent)

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

This is not so bad.

But yes, I was upset by this.

0
source

All Articles