5

最近我需要在 HTML 文档的节点上评估 XQuery。基本上,我需要从 body 元素的第一个子元素中选择具有 href 属性的所有元素。我添加了一个小例子来解释:

<html>
    <body>
        <a href="http://www.google.be"/>
    </body>
</html>

在这种情况下,所需的提取结果显然是:

<a href="http://www.google.be"/>

我的第一个想法是使用//body/*[1]//*[@href],因为:

  • //body匹配 body 元素,无论它在哪里
  • /*[1]匹配 body 元素的第一个子元素
  • //*[@href]匹配当前元素的所有后代或自身

我认为这可行,但在提供的示例中,XQuery 没有给出任何结果。

但是,我阅读了一下,发现以下内容(来源:http ://www.keller.com/xslt/8/ ):

Alternate notation for "//": descendant-or-self::node()

所以我将我的 XQuery 更改为//body/*[1]/descendant-or-self::node()[@href],这一次,结果是正确的。

我的问题://和descendant-or-self::node()有什么区别?我在这里找到的(What's the difference between //node and /descendant::node in xpath?)和这里(http://www.w3.org/TR/xpath/#axes)说:

//是 的缩写/descendant-or-self::node()/。例如,//para是 的缩写/descendant-or-self::node()/child::para

这使我得出结论//并且/descendant-or-self::node()不可互换(可能是因为最后终止/了?),但是有人可以告诉我是否有简写/descendant-or-self::node()吗?

4

2 回答 2

5

您的第一个 XPath 表达式 ( //body/*[1]//*[@href]) 实际上代表了您用自然语言描述的内容://body/*[1]是 body 元素的第一个子元素,并//*[@href]选择第一个具有@href属性的元素(如下)。

在您的示例中,锚标记下方没有具有此类属性的元素。例如,此查询将匹配

<html>
    <body>
        <p>
            <a href="http://www.google.be"/>
        </p>
    </body>
</html>

此查询的非缩写版本是:

//body/*[1]/descendant-or-self::node()/*[@href]

对比第二个查询,问题应该很容易看出:

//body/*[1]/descendant-or-self::node()[@href]
于 2014-01-20T18:38:54.050 回答
1

我认为问题出在您的描述中,它似乎与您的示例不符!

给定输入:

<html>
    <body>
        <a href="http://www.google.be"/>
    </body>
</html>

和要求声明:

“body 元素的第一个子元素中具有 href 属性的所有元素”

您的 XPath 公式为:

//body/*[1]//*[@href]

符合您的要求声明。但是,预期的输出将是一个空序列,正如您所发现的那样......而不是您建议的输出:

<a href="http://www.google.be"/>

要获得建议的输出,您的 XPath 需求声明可能改为:

“具有 href 属性的 body 元素的第一个子元素”,这将导致 XPath:

//*[@href][parent::body][1]

从您的需求声明和不匹配的示例中,很难确定您的意思。所以也许你的需求声明是:

“正文中具有 href 属性的第一个元素”

如果是这种情况,那么我建议使用 XPath:

($input//*[@href][ancestor::body])[1]

请注意,序列构造函数,即 '(' 和 ')' 将后代序列展平,以允许您以类似于数组的方式寻址每个选定的后代。

于 2014-01-21T00:20:57.803 回答