考虑以下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呢?另外,有没有人对如何解决这个问题有任何建议?
谢谢。
这个谜现在已经解决了。
有问题的节点是在另一个函数中重新创建的,该函数的结果是剥夺了它的所有祖先信息。不幸的是,以前的开发人员没有记录这个奇妙的,很少的功能,并且花费了我们很多时间。
因此,祖先轴完全按照预期工作 - 它只是应用于欺骗性节点。
我感谢你们所有人回答我的问题。
答案 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中通常不是一个好主意,因为它会影响你的输入和输出)