如何一次性替换XML的多个节点?数据中心框架

How to Replace multiple nodes of XML in one go ? DATA HUB FRAMEWORK

我在暂存数据库中有几个文档。

根据条件,我需要检查 FINAL 中是否存在具有相同 ID 的文档。

如果是,那么我需要将文档的多个节点从 STAGING 替换为 FINAL,然后插入它。

DOC from STAGING-
<root>
 <ID>1</ID>
 <value1>India</value1>
 <value2>USA</value2>
 <value3>Russia</value3>
 <value4>Srilanka</value4>
 <value5>Europe</value5>
 <value6>Antartica</value6>
 <value7>Spain</value7>
</root>

DOC from FINAL-
<root>
 <ID>1</ID>
 <value1></value1>
 <value2></value2>
 <value3></value3>
 <value4></value4>
 <value5>Europe</value5>
 <value6>Antartica</value6>
</root>

我期待最终的输出-

<root>
 <ID>1</ID>
 <value1>India</value1>
 <value2>USA</value2>
 <value3>Russia</value3>
 <value4>Srilanka</value4>
 <value5>Europe</value5>
 <value6>Antartica</value6>
 <value7>Spain</value7>
</root>

从 STAGING 我只需要关注 (value1,value2,value,value4,value7) 并替换它。对于其他值,我有一些不同的条件,所以我不得不忽略它们。

我在WRITER.xqy-

中写的逻辑
  let $boolean := fn:false()
  let $var := if((......)
             then
                (
                    let $docs :=
                                   cts:search(doc(),cts:and-query((
                                                                        cts:element-value-query(xs:QName("ID"),$id),
                                                                        cts:collection-query(("MyCollection"))
                                                                   ))) 
                    let $temp := 
                                    if((fn:exists($result) eq fn:true())) then xdmp:set($boolean,fn:true()) else ()
                    return $docs


                ) 
            else ()

let $envelope := if($boolean) 
                    then
                        (
                        let $nodes := ("value1,value2,value,value4,value7")
                        let $tokenize := fn:tokenize($nodes,",")
                        let $values := for $i in $tokenize
                                       let $final :=  xdmp:value(fn:concat("$var//*:root/*:",$i))
                                       let $staging :=  xdmp:value(fn:concat("<",$i,">","{$envelope//*:root/*:",$i,"/text()}","</",$i,">"))
                                       let $envelope := mem:node-replace($final,$staging) 
                                       return $envelope
                        return $values
                        ) 
               else $envelope
return
xdmp:document-insert($id,$envelope, xdmp:default-permissions(), map:get($options, "entity"))

这给了我

ERROR- ARG2 for xdmp:document-insert is NOT a NODE.

我确实理解它,因为我的 $envelope 正在迭代所有节点并返回多个信封。

有什么解决这个问题的建议吗?

当你使用in-mem-update函数时,它returns修改的结果。

如果您要对文档进行一系列更改,则需要使用前一个 mem:* 方法调用的结果作为下一个方法调用的输入。您可以通过一个递归函数来实现这一点,该函数要么使用一个更少的元素名称调用自身,要么 returns 没有更多名称时的最终结果。

下面是如何完成的示例。我还简化了一些逻辑,使用 XPath 来 select 所需的元素,并在 local-name() 上使用谓词过滤器,而不是生成字符串并使用 xdmp:value() 进行评估。我认为它更简单易读。

import module namespace mem    = "http://xqdev.com/in-mem-update" 
    at '/MarkLogic/appservices/utils/in-mem-update.xqy';

declare function local:replace-elements($final-doc, $staging-doc, $element-names) {
  if (fn:empty($element-names)) then 
    $final-doc
  else
    let $name := fn:head($element-names)
    let $final :=  $final-doc//*:root/*[local-name() = $name]
    let $staging :=  $staging-doc//*:root/*[local-name() = $name]
    let $final-updated :=
      if ($final) then 
        mem:node-replace($final, $staging)
      else (: the element doesn't exist in the final doc :)
        (: insert the staging element as a child of the root element :)
        mem:node-insert-child($final-doc//*:root, $staging) 
        (: Otherwise, if you don't want to add the staging element, return $final-doc instead of inserting :)
    return
      local:replace-elements(document{$final-updated}, $staging-doc, fn:tail($element-names)) 
};

let $boolean := fn:false()
let $var := 
  if ((......) then
    (
      let $docs :=
        cts:search(doc(), cts:and-query((
          cts:element-value-query(xs:QName("ID"), $id),
          cts:collection-query("MyCollection")
        ))) 
      let $temp := 
        if ((fn:exists($result) eq fn:true())) then 
          xdmp:set($boolean,fn:true()) 
        else ()
      return $docs
    ) 
  else ()

let $envelope := 
  if ($boolean) then
    let $nodes := ("value1,value2,value3,value4,value7")
    let $element-names := fn:tokenize($nodes,",")
    return
      local:replace-elements($var, $envelope, $element-names)
  else $envelope

return
    xdmp:document-insert($id,$envelope, xdmp:default-permissions(), map:get($options, "entity"))