如何一次性替换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"))
我在暂存数据库中有几个文档。
根据条件,我需要检查 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"))