3

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.

4

1 回答 1

4

我找到的最佳答案是在Evan Lenz的一封旧电子邮件中。

作为对 XPath 在这方面的工作原理以及 XPath 1.0 规范如何向我们展示答案的解释,值得一读。但执行摘要在此规则中:

Step    ::=    AxisSpecifier NodeTest Predicate*
                  | AbbreviatedStep

Step 产生式定义了location step的语法,并且仅在 location step 内应用轴的反向。除了 nodetest 和 predicates 之外,任何出现在轴和位置谓词之间的语法都会破坏链并且方向将恢复为正向。

这就解释了为什么如果你在 a 周围加上括号preceding::foo并在括号外附加一个位置谓词,位置谓词会忽略preceding::轴的方向。

它还解释了为什么我今天在代码中的第一次尝试成功了,尽管我的期望是:您可以在 NodeTest 之后放置任意数量的谓词,并且轴的方向仍然适用于所有谓词。

于 2013-08-30T02:41:27.647 回答