0

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.

Ilya Kozhevnikov
  • 10,242
  • 4
  • 40
  • 70
  • In what way does Firefox "fail"? Perhaps [this](http://stackoverflow.com/questions/25407504/what-is-the-difference-between-or-and-when-programming-in-xslt/25407704#25407704) also helps you understand the difference? – Mathias Müller Jan 07 '15 at 15:17
  • @MathiasMüller Thanks, seems that Chrome is wrong here as spec explicitly states document order. Need to find another way for a "lazy" selector. – Ilya Kozhevnikov Jan 07 '15 at 15:35
  • 1) node-set is an unordered list of nodes - it is up to implementation to decide how to order the selected nodes, usually they preserve DOM order; 2) the specification does not define the order of node-set produced by | operator, so its again up to implementation to handle that. Chrome and FF both adhere to spec, in different ways though – comeGetSome Jan 07 '15 at 15:35
  • No, the spec does not state document order. Are you looking at the XPath 2.0 spec? – Mathias Müller Jan 07 '15 at 15:38
  • @MathiasMüller http://www.w3.org/TR/xpath-functions/#func-union – Ilya Kozhevnikov Jan 07 '15 at 15:46
  • @IlyaKozhevnikov Look at the page title: "XPath **2.0** Functions and Operators" – Mathias Müller Jan 07 '15 at 15:46

2 Answers2

1

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

comeGetSome
  • 1,913
  • 19
  • 20
1

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.

Community
  • 1
  • 1
Mathias Müller
  • 22,203
  • 13
  • 58
  • 75