问题
I am having several documents in STAGING DB.
Based on a condition i need to check if the document with same ID exist in FINAL.
If it does then i need to replace the multiple nodes of document from STAGING to FINAL and then insert it.
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 i am expecting in 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>
From the STAGING i just need to focus on (value1,value2,value,value4,value7) and replace it. For other values i am having some different conditions so i have to ignore them.
Logic i have written in 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"))
This gives me
ERROR- ARG2 for xdmp:document-insert is NOT a NODE.
I do understand it as my $envelope
is iterating for all the NODES and returning multiple envelopes.
Any Suggestions to resolve this ?
回答1:
When you use the in-mem-update function, it returns the result of the modification.
If you are going to be making a sequence of changes to the document, you need to use the product of the previous mem:* method calls as the input for the next. You can achieve that with a recursive function that either calls itself with one less element name, or returns the final result when there are no more names.
Below is an example of how it could be done. I also simplified some of the logic to use XPath to select the desired elements with a predicate filter on the local-name()
, instead of generating strings and evaluating with xdmp:value()
. I think that it's more straightforward and easier to read.
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"))
来源:https://stackoverflow.com/questions/51998598/how-to-replace-multiple-nodes-of-xml-in-one-go-data-hub-framework