You Old Fool
You Old Fool

Reputation: 22950

How can I match either of two elements in part of an XPath query

I have using php DOMXPath to query for an anchor and want to match either one of two elements. I am currently doing it like this with a pipe or condition:

//div[@class="wrapper"]//div[@class="target"]/a | //div[@class="wrapper"]//li[@class="target"]/a

This works. I've also tried this (as outlined here):

//div[@class="wrapper"]//*[self::div or self::li][@class="target"]/a

While this does work, it seems inefficient since it uses a wildcard to query every element and then filters them after the fact.

To be more concise I'm wondering if it's possible to shorten my original query so that my | condition only applies to a specific part, instead of repeating the entire query. I thought I would be able to do something like this, but it throws an error DOMXPath::query(): Invalid expression:

//div[@class="wrapper"]//(div|li)[@class="target"]/a

Is this possible with the correct syntax or do I need to explicitly state the entire path for each condition?

Upvotes: 1

Views: 530

Answers (1)

Mads Hansen
Mads Hansen

Reputation: 66723

//div[@class="wrapper"]//(div|li)[@class="target"]/a is a valid XPath 2.0 expression, but not XPath 1.0. Your PHP engine is likely to be relegated to XPath 1.0.

If you are worried about the performance of your second XPath //div[@class="wrapper"]//*[self::div or self::li][@class="target"]/a, first profile and measure to see if it performs within an acceptable ranges. You may find that it performs well enough, or the same as your first example, and that you don't need to worry about the difference.

Alternatives that you could also test and measure performance would be to move the predicate restricting to elements that have a class attribute equal to "target" before the predicate testing the div or li elements:

//div[@class="wrapper"]//*[@class="target"][self::div or self::li]/a

or combine them in a single predicate:

//div[@class="wrapper"]//*[@class="target" and (self::div or self::li)]/a

Upvotes: 2

Related Questions