XQuery祖先轴不起作用,但显式XPath确实如此

时间:2012-01-03 16:51:21

标签: xpath xquery marklogic axes

考虑以下XML代码段:

<doc>
    <chapter id="1">
        <item>
            <para>some text here</para>
        </item>
    </chapter>
</doc>

XQuery中,我有一个函数,需要根据给定&#34; para&#34;的祖先章节做一些事情。作为参数传入的元素,如下面的剥离示例所示:

declare function doSomething($para){
    let $chapter := $para/ancestor::chapter
    return "some stuff"
};

在该示例中, $ chapter 一直空着。但是,如果我写下类似于下面的函数(即,不使用祖先轴),我会得到所需的&#34;章节&#34;元素:

declare function doSomething($para){
    let $chapter := $para/../..
    return "some stuff"
};

问题是我不能像后一个例子中那样使用显式路径,因为我将要搜索的XMl不能保证&#34;章节&#34;元素作为祖父母每次。它可能是曾祖父母曾祖父母等等,如下所示:

<doc>
    <chapter id="1">
        <item>
            <subItem>
                <para>some text here</para>
            </subItem>
        </item>
    </chapter>
</doc>

有没有人解释为什么轴不起作用,而显式XPath呢?另外,有没有人对如何解决这个问题有任何建议?

谢谢。


解:

这个谜现在已经解决了。

有问题的节点是在另一个函数中重新创建的,该函数的结果是剥夺了它的所有祖先信息。不幸的是,以前的开发人员没有记录这个奇妙的,很少的功能,并且花费了我们很多时间。

因此,祖先轴完全按照预期工作 - 它只是应用于欺骗性节点。

我感谢你们所有人回答我的问题。

4 个答案:

答案 0 :(得分:4)

祖先轴确实可以正常工作。我怀疑你的问题是命名空间。您展示的示例和我运行的示例(如下所示)具有没有任何名称空间的XML。如果你的XML有一个命名空间,那么你需要在祖先 XPath 中提供它,如下所示:$para/ancestor:foo:chapter在这种情况下,prefix _foo_ is绑定到正确的命名空间章节元素。

let $doc := <doc>
    <chapter id="1">
        <item>
            <para>some text here</para>
        </item>
    </chapter>
</doc>

let $para := $doc//para
return $para/ancestor::chapter

结果:

<?xml version="1.0" encoding="UTF-8"?>
<chapter id="1">
  <item>
    <para>some text here</para>
  </item>
</chapter>

答案 1 :(得分:2)

这些东西几乎总是归结为名称空间!作为确认100%命名空间不是问题的诊断,您可以尝试:

declare function local:doSomething($para) {
    let $chapter := $para/ancestor::*[local-name() = 'chapter']
    return $chapter
};

答案 2 :(得分:1)

这对我来说似乎很令人惊讶;你使用哪个XQuery实现?使用BaseX,以下查询...

declare function local:doSomething($para) {
    let $chapter := $para/ancestor::chapter
    return $chapter
};

let $xml :=
  <doc>
    <chapter id="1">
        <item>
            <para>some text here</para>
        </item>
    </chapter>
</doc>
return local:doSomething($xml//para)

...返回...

<chapter id="1">
  <item>
    <para>some text here</para>
  </item>
</chapter>

答案 3 :(得分:1)

我也怀疑名称空间。如果$para/../..有效但$para/parent::item/parent::chapter为空,那么您就知道这是名称空间的问题。

在内容的顶部查找xmlns声明,例如:

<doc xmlns="http://example.com">
  ...
</doc>

在您的XQuery中,您需要将该命名空间绑定到前缀并在XQuery / XPath表达式中使用该前缀,如下所示:

declare namespace my="http://example.com";
declare function doSomething($para){
  let $chapter := $para/ancestor::my:chapter
  return "some stuff"
};

您使用的前缀无关紧要。重要的是名称空间URI(上例中的http://example.com)匹配。

../..选择所需的元素是有道理的,因为..parent::node()的缩写,它选择父节点而不管其名称(或命名空间)。而ancestor::chapter只会选择不在命名空间中的<chapter>个元素(除非你已经声明了一个默认元素命名空间,这在XQuery中通常不是一个好主意,因为它会影响你的输入和输出)