When we have multiple terms to locate an element we can use a single predicate with logical and operator inside it or to use multiple predicates with single term inside each predicate.
For example on this page we can locate links to questions containing selenium
in their links with this XPath:
"//a[@class='s-link'][contains(@href,'selenium')]"
and with this
"//a[@class='s-link' and contains(@href,'selenium')]"
I'm wondering if there are any differences between these 2 approaches?
CodePudding user response:
The expressions are equivalent provided that neither of the predicates is positional. A predicate is positional if (a) its value is numeric, or (b) its value depends on the current position in the dynamic context (for practical purposes, that means if it's an expression that calls the position()
function).
Assuming this condition is met, there is no good reason for preferring one expression over the other. It's possible of course that some XPath processor might evaluate one of them faster than the other, but it's very unlikely to be a signficant difference, and it could equally well favour either of the two.
There are minor differences in the degree of freedom offered to processors in how far they can go in optimising the constructs in ways that affect error handling, and these rules vary slightly between XPath versions, but again this is very unlikely to be significant in practice.
The equivalence doesn't apply to positional predicates because (a) when you write A[X][Y]
, the value of position()
within Y
is different from its value within X
, and (b) if X
or Y
is numeric then it is interpreted as position()=X
(or position()=Y
), and this doesn't apply to the operands of and
: you can't rewrite A[@code][1]
as A[@code and 1]
.
CodePudding user response:
There may be differences in the algorithm that evaluates these expressions, but the result is the same. Things would be different if the second condition contained position()
or last()
:
//a[@class='s-link'][position() > 1]
gives alls-link
anchors except the first (becauseposition()
is the position in the nodeset//a[@class='s-link']
) whereas//a[@class='s-link' and position() > 1]
gives alls-link
anchors that come after the first anchor overall (becauseposition()
is the position in the nodeset//a
).
Also, you can select the first s-link
anchor with //a[@class='s-link'][1]
, but not with //a[@class='s-link' and 1]
.