使用 XQuery 删除 xml 个节点
Remove xml nodes using XQuery
我有以下 xml:
<?xml version="1.0" encoding="UTF-8"?>
<publication>
<scientificPublication>
<id>2347823476</id>
<book>
<chapter>
<author>Tom</author>
<genre>Java</genre>
<genre>Webservice</genre>
</chapter>
</book>
<book>
<chapter>
<author>Mike</author>
<genre>C</genre>
<genre>Machine Learning</genre>
</chapter>
</book>
<book>
<chapter>
<author>William</author>
<genre>JavaScript</genre>
<genre>Frontend</genre>
</chapter>
</book>
</scientificPublication>
</publication>
我需要使用 XQuery 过滤 xml,所以最终得到以下结果:
<?xml version="1.0" encoding="UTF-8"?>
<publication>
<scientificPublication>
<id>2347823476</id>
<book>
<chapter>
<author>Tom</author>
<genre>Java</genre>
<genre>Webservice</genre>
</chapter>
</book>
</scientificPublication>
</publication>
基本上我的想法是找到第一本书中的所有兄弟节点,然后使用函数 fn:remove((item,item,...),position)
删除它们。所以我用下面的xpath找到了所有需要删除的节点:
publication/*/book[not(./*[(genre='Java')and(genre='Webservice')])]
然后我尝试使用以下代码将它们从 xml 中删除:
declare function local:process-xml($element) {
let $orig := $element
let $toFilter := $element/*/book[not(./*[(genre='Java')and(genre='Webservice')])]
let $el := local:filter($orig, $toFilter)
return $el
};
declare function local:filter($elements, $toFilter) {
for $i in $toFilter
let $pos := position()
remove($lements, $pos)
return $elements
};
当我尝试执行此操作时,我收到一条错误消息,提示他已停止,期望在第二个函数上出现 'return'。
有人知道我在这种情况下做错了什么吗?
您的整个方法本质上感觉不太实用。使用 BaseX 删除元素最好使用 XQuery Update.
因此,在您的情况下,您只需使用以下函数删除所有书籍元素:
declare function local:process-xml($element) {
$element update delete node .//book[not(./*[(genre='Java')and(genre='Webservice')])]
};
您可以使用递归函数过滤掉 book
个元素:
declare function local:filter($node)
{
typeswitch($node)
case element(book) return
if ($node[not(*[(genre='Java') and (genre='Webservice')])])
then () (: we don't want these books, so return empty sequence :)
else $node (: this is the book we want :)
case element() return
element { fn:node-name($node) } {
$node/@*,
$node/node() ! local:filter(.)
}
default return $node
};
我有以下 xml:
<?xml version="1.0" encoding="UTF-8"?>
<publication>
<scientificPublication>
<id>2347823476</id>
<book>
<chapter>
<author>Tom</author>
<genre>Java</genre>
<genre>Webservice</genre>
</chapter>
</book>
<book>
<chapter>
<author>Mike</author>
<genre>C</genre>
<genre>Machine Learning</genre>
</chapter>
</book>
<book>
<chapter>
<author>William</author>
<genre>JavaScript</genre>
<genre>Frontend</genre>
</chapter>
</book>
</scientificPublication>
</publication>
我需要使用 XQuery 过滤 xml,所以最终得到以下结果:
<?xml version="1.0" encoding="UTF-8"?>
<publication>
<scientificPublication>
<id>2347823476</id>
<book>
<chapter>
<author>Tom</author>
<genre>Java</genre>
<genre>Webservice</genre>
</chapter>
</book>
</scientificPublication>
</publication>
基本上我的想法是找到第一本书中的所有兄弟节点,然后使用函数 fn:remove((item,item,...),position)
删除它们。所以我用下面的xpath找到了所有需要删除的节点:
publication/*/book[not(./*[(genre='Java')and(genre='Webservice')])]
然后我尝试使用以下代码将它们从 xml 中删除:
declare function local:process-xml($element) {
let $orig := $element
let $toFilter := $element/*/book[not(./*[(genre='Java')and(genre='Webservice')])]
let $el := local:filter($orig, $toFilter)
return $el
};
declare function local:filter($elements, $toFilter) {
for $i in $toFilter
let $pos := position()
remove($lements, $pos)
return $elements
};
当我尝试执行此操作时,我收到一条错误消息,提示他已停止,期望在第二个函数上出现 'return'。 有人知道我在这种情况下做错了什么吗?
您的整个方法本质上感觉不太实用。使用 BaseX 删除元素最好使用 XQuery Update.
因此,在您的情况下,您只需使用以下函数删除所有书籍元素:
declare function local:process-xml($element) {
$element update delete node .//book[not(./*[(genre='Java')and(genre='Webservice')])]
};
您可以使用递归函数过滤掉 book
个元素:
declare function local:filter($node)
{
typeswitch($node)
case element(book) return
if ($node[not(*[(genre='Java') and (genre='Webservice')])])
then () (: we don't want these books, so return empty sequence :)
else $node (: this is the book we want :)
case element() return
element { fn:node-name($node) } {
$node/@*,
$node/node() ! local:filter(.)
}
default return $node
};