我需要一个能够重写文档的XQuery函数,特别是返回子节点的子集,基于指定要检索的节点名称的字符串数组。如果应该满足如下定义并且需要使用任何任意文档。
local:apply-node-includes($document, $includedNodeNames as xs:string*)
鉴于我有一些xml doc
let $doc :=
<foo a="b">
<bar>hello</bar>
<baz>1</baz>
<bang>
<text>world</text>
</bang>
</foo>')
然后该函数应该转换文档,以便只返回在$ includedNodes中指定名称的子节点。
示例local:apply-node-includes($doc, 'baz')
将返回
<foo a="b">
<baz>1</baz>
</foo>
示例local:apply-node-includes($doc, ('bar','bang')))
将返回
<foo a="b">
<bar>hello</bar>
<bang>
<text>world</text>
</bang>
</foo>
我尝试迭代节点,和/或使用某种形式的递归类型切换,但到目前为止还无法做到正确。如果它完全递归地工作会非常酷,所以'bang.text'将只包括孙子文本节点,而不是它们的任何兄弟节点,但也许这要求太多了!
答案 0 :(得分:1)
我不确定这是否是最优雅的解决方案,但似乎符合您的要求。此处的函数重新创建传递文档的根元素,然后包含任何直接子元素(及其所有属性和子元素),其元素名称与传递列表中的任何字符串匹配。
declare function local:apply-node-includes( $doc as item(), $includedNodeNames as xs:string*) as item()
{
(: Recreate the root element :)
element {name($doc)}
{ (: Replicate root element's attributes :)
(for $attribute in $doc/@* return $attribute),
(: Replicate root element's immediate children having any of given names :)
(for $element in $doc/* where name($element) = $includedNodeNames
return $element)
}
};
let $doc :=
<foo a="b">
<bar>hello</bar>
<baz>1</baz>
<bang>
<text>world</text>
</bang>
</foo>
return local:apply-node-includes($doc, ('bar','bang'))
输出:
<foo a="b"><bar>hello</bar><bang><text>world</text></bang></foo>
答案 1 :(得分:1)
declare function local:apply-node-includes($doc as element(), $includedNodeNames as xs:string*) as element()?
{
element {node-name($doc) }
{
$doc/@*,
$doc/*[name(.)=$include-names]
}
};
这本书对这个主题非常有用 https://en.wikibooks.org/wiki/XQuery/Filtering_Nodes并演示了你需要能够处理孙子问题部分的递归身份转换。