Exactly when is the reverse axis direction applied?

Those who are familiar with XPath know that some axes, such as preceding::

, are reverse axes. And if you put a positional predicate on an expression built with a reverse axis, you can count backwards, not forward. For example.

$foo/preceding-sibling::*[1]

      

returns the previous sibling element immediately before $foo

, rather than the first preceding sibling element (in document order).

But then you run into variations in which this rule seems to be broken, depending on how far away the positional predicate is from the back axis. For example.

($foo/preceding-sibling::*)[1]

      

counts forward from the beginning of the document, not backward from $foo

.

Today I was writing some code where I had an expression like

$foo/preceding::bar[not(parent::baz)][1]

      

I wanted to report back from $foo

. But was my positional predicate too far off axis preceding::

? If the expression had lost direction before I added [1]

? I thought it probably wouldn't work, so I changed it to

$foo/preceding::bar[not(parent::baz)][last()]

      

but then I was not sure about that direction, so I put in parentheses to make sure:

($foo/preceding::bar[not(parent::baz)])[last()]

      

However, the extra parentheses get a little confusing, and I thought the expression might be less efficient if you actually need to count from the beginning of the (large) input document instead of backwards from $foo

. Should I do it like this?

Finally, I tested the original expression and was surprised to find that it worked! Thus, the intervention [not(parent::baz)]

did not cause the expression to lose its reverse direction.

This problem has been resolved, but I have come to a point where I would like to get better control, when I can expect the opposite direction of the axis. My question is: At what point (s) does an XPath expression using a reverse axis lose direction?

I believe I have found the answer now, so I will answer my own question. But I couldn't find an answer on SO, and that's what bothered me long enough to be interesting to ask and answer here.

+2


source to share


1 answer


The best answer I found was in an old email from Evan Lenz .

It is worth reading in full how an explanation of how XPath works in this regard, and how the XPath 1.0 specification shows us the answer. But the executive summary is in this rule:

Step    ::=    AxisSpecifier NodeTest Predicate*
                  | AbbreviatedStep

      



Derived Step defines the syntax of the location step and only at the location step in which the opposite direction of the axis is applied. Any syntax that falls between an axis and a positional predicate other than nodetest and predicates will break the chain and the direction will go back forward.

This explains why if you put parentheses around preceding::foo

and add a positional predicate outside the parentheses, the positional predicate ignores the axis direction preceding::

.

This also explains why my first attempt at my code today worked despite my expectations: you can put as many predicates after the NodeTest as you like and the axis direction will still apply to all of them.

+3


source







All Articles