如何一气呵成替换XML的多个节点? 数据中心框架(How to Replace multiple

2019-09-26 03:09发布

我有分期DB几个文件。

基于一个条件,我需要检查是否有相同ID的文档中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>

OUTPUT我期待在FINAL-

<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>

从阶段我只需要专注于(值1,值,值,值4,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"))

这给了我

对于xdmp ERROR- ARG2:文档插入不是一个节点。

我把它理解为我的$envelope被遍历所有节点,并返回多个信封。

任何建议,以解决此问题?

Answer 1:

当您使用在-MEM-更新功能,它返回修改的结果。

如果你将要在更改文件的顺序,你需要使用以前的MEM的产品:*方法调用输入下一个。 可以实现与递归函数,要么少了一个元素名自称,或当没有更多的名字返回最终结果。

下面是它如何工作的一个示例。 我还简化了一些逻辑的使用XPath来选择与上一个过滤器谓语所需元件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"))


文章来源: How to Replace multiple nodes of XML in one go ? DATA HUB FRAMEWORK