I have XML documents like:
<rootelement>
<myelement>test1</myelement>
<myelement>test2</myelement>
<myelement type='specific'>test3</myelement>
</rootelement>
I’d like to retrieve the specific myelement, and if it’s not present, then the first one. So I write:
/rootelement/myelement[@type='specific' or position()=1]
The XPath spec states about the ‘or expression’ that:
The right operand is not evaluated if
the left operand evaluates to true
The problem is that libxml2-2.6.26 seems to apply the union of both expressions, returning a “2 Node Set” (for example using xmllint --shell).
Is it libxml2 or am I doing anything wrong ?
Short answer: your selector doesn’t express what you think it does.
The
oroperator is a union.The part of the spec you quoted (“The right operand is not evaluated…”) is part of standard boolean logic short circuiting.
Here’s why you get a 2-node set for your example input: XPath looks at every
myelementthat’s a child ofrootelement, and applies the[@type='specific' or position()=1]part to each such node to determine whether or not it matches the selector.<myelement>test1</myelement>does not match@type='specific', but it does matchposition()=1, so it matches the whole selector.<myelement>test2</myelement>does not match@type='specific', and it also does not matchposition()=1, so it does not match the whole selector.<myelement type='specific'>test3</myelement>matches@type='specific'(so XPath does not have to test its position – that’s the short-circuiting part) so it matches the whole selector.The first and last
<myelement>s match the whole selector, so it returns a 2-node set.The easiest way to select elements the way you want to is to do it in two steps. Here’s the pseudocode (I don’t know what context you’re actually using XPath in, and I’m not that familiar with writing XPath-syntax selectors):
elementsthat match/rootelement/myelement[@type='specific']elementsis empty, selectelementsthat match/rootelement/myelement[position()=1]