【问题标题】:Remove xml nodes using XQuery使用 XQuery 删除 xml 节点
【发布时间】:2020-06-08 14:21:08
【问题描述】:

我有以下 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
};

当我尝试执行此操作时,我收到一条错误消息,说他停止了,期待第二个函数“返回”。 有人知道我在这种情况下做错了什么吗?

【问题讨论】:

    标签: xml xquery basex


    【解决方案1】:

    您的整个方法在本质上并不实用。使用 BaseX 删除元素最好使用 XQuery Update

    因此,在您的情况下,您只需使用以下函数删除所有书籍元素:

    declare function local:process-xml($element) {
      $element update delete node .//book[not(./*[(genre='Java')and(genre='Webservice')])] 
    };
    

    【讨论】:

    • 这将从数据库中删除元素。在我的情况下,从数据库中检索完整的 xml,然后从这一点开始,我必须过滤结果,在数据库中保持原始不变。
    • 不,它根本不会改变数据库。它是一个非更新表达式,由“update”关键字表示。您可以在我提供的 BaseX 文档的链接中找到更多相关信息,
    • 当我运行这个时,我得到错误:org.basex.core.BaseXException: Stopped at ., 101/31: [XUDY0014] Node is not created by copy clause: element {... }.
    • 当您运行完全相同的函数时,我很难相信您会收到此错误消息。此错误消息表明您在更新部分(而不是点)中使用了变量 $element。我在 BaseX 9.3.3 中对此进行了测试。如果您确定您正在运行的是相同的,请提供(编辑您的问题)您执行的确切代码和您使用的 BaseX 版本。
    【解决方案2】:

    您可以使用过滤掉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
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-05
      • 2021-05-31
      • 1970-01-01
      相关资源
      最近更新 更多