Reputation: 10432
How would one make XPath (1) one-liner prioritisation work in Firefox? Why does |
"fails" in Firefox but "works" in Chrome?
Which one is right (if this behaviour defined in the spec) and how to get it working across the board?
<a>b</a>
<a id="b"></a>
Chrome 39.0.2171.95
> $x("//a[@id='b'] | //a[text()='b']")
< [<a id="b"></a>, <a>b</a>]
Firefox 34.0.5
> $x("//a[@id='b'] | //a[text()='b']")
< Array [ <a>, <a#b> ]
Edit: removed the or
selector example as question is about |
behaviour in Firefox and not about the difference between the two.
Upvotes: 0
Views: 210
Reputation: 22617
I can only quote Dr. Michael Kay, saying:
The XPath 1.0 specification defines that a path expression (or a union expression) returns a node-set, that is, an unordered set of nodes. Some host languages, for example XSLT 1.0, specify that node-sets are always processed in document order. But you appear (as far as I can tell) to be invoking XPath from some Microsoft API, and I've no idea what that API says about the processing order: it's up to the XPath host language to define it, or it could choose to leave it undefined.
And, if major browsers should ever adopt XPath 2.0:
This changes in XPath 2.0, which specifies that path expressions and union expressions return a sequence of distinct nodes in document order.
In your case, this simply means: Do not use the |
or union
operator if the order of the result set and duplicates matter to you. Use a predicate that contains or
(the path expressions you have now edited out of your question) if such an expression return the results in the same order for both Firefox and Chrome.
But in general, the document order cannot be guaranteed for node-sets, since unorderedness is a property of sets:
The second important point is that the order in which the elements of a set are listed is irrelevant (unlike for a sequence or tuple) (from: Set(mathematics)).
Still, many implementations of XPath 1.0 return the "items" in a node-set in document-order - not because they are obliged to do so by the specification, but because in many cases, returning results in document order really makes sense.
There are several very similar questions already, for example this question or this one.
Upvotes: 1
Reputation: 1963
the | operator is not an or, it is a union, hence the node-set would contain a subset of elements selected by left hand xpath (left side of pipe) and the right hand xpath.
the selector
"//a[@id='b' or text()='b']"
reads: traverse all "a" elements in the order they appear in DOM and evaluate the predicate [..], if the predicate evaluates to 'true', the traversed element is added to result node-set
the selector
"//a[@id='b'] | //a[text()='b']"
reads: apply //a[@id='b'] (as described above), then apply //a[text()='b'] and finally join the results together returning a node-set containing both results.
the order of elements in the result is the same of traversion i.e. it preserves the order in document, however the union does not include duplicates (since a node-set may not contain duplicates), i.e. //a|//a results in same node-set
however, it is not defined how union (|) should handle order, hence its up to implementation, therefore you see different results in Chrome vs FF
Upvotes: 1