Exactly when does the reverse direction of an axis apply?

不问归期 提交于 2020-01-01 17:27:13

问题


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 may be counting backward instead of forward. E.g.

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

returns the preceding sibling element just before $foo, not the first preceding sibling element (in document order).

But then you encounter variations where this rule seems to be broken, depending on how far removed the positional predicate is from the reverse axis. E.g.

($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 be counting backwards from $foo. But was my positional predicate too far removed from the preceding:: axis? Had the expression lost its reverse direction before I added the [1]? I thought it probably wouldn't work, so I changed it to

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

but then I wasn't really sure of the direction, so I put in parentheses to make sure:

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

However, the extra parentheses are a bit confusing, and I thought the expression might be less efficient, if it really has to count from the beginning of the (large) input document instead of backward from $foo. Was it really necessary to do it this way?

Finally I tested the original expression, and found to my surprise that it worked! So the intervening [not(parent::baz)] had not caused the expression to lose its reverse direction after all.

That problem was solved, but I've come to the point where I'd like to get a better handle on when I can expect the reverse direction of an axis to apply. My question is: At what point(s) does an XPath expression using a reverse axis lose its reverse direction?

I believe I've found the answer now, so I'll answer my own question. But I couldn't find the answer on SO, and it's something that has bothered me long enough that it was worth asking and answering here.


回答1:


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

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

Step    ::=    AxisSpecifier NodeTest Predicate*
                  | AbbreviatedStep

The Step production defines the syntax of a location step, and it's only within a location step that the reverse direction of an axis applies. Any syntax that comes between the axis and a positional predicate, other than the nodetest and predicates, will break the chain and the direction will revert to forward.

This explains why, if you put parentheses around a preceding::foo and append a positional predicate outside the parentheses, the positional predicate ignores the direction of the preceding:: axis.

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



来源:https://stackoverflow.com/questions/18524096/exactly-when-does-the-reverse-direction-of-an-axis-apply

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!