3
votes

I want to update an XML document in my xml database (Marklogic). I have xml as input and want to replace each node that exists in the target xml.

If a node does not exist it would be great if it gets added, but thats maybe another task.

My XML in the database:

<user>
  <username>username</username>
  <firstname>firstname</firstname>
  <lastname>lastname</lastname>
  <email>email@mail.de</email>
  <comment>comment</comment>
</user>

The value of $user_xml:

<user>
  <firstname>new firstname</firstname>
  <lastname>new lastname</lastname>
</user>

My function so far:

declare function update-user (
    $username as xs:string,
    $user_xml as node()) as empty-sequence()
{
    let $uri := user-uri($username)
    return
        for $node in $user_xml/user
        return 
            xdmp:node-replace(fn:doc($uri)/user/fn:node-name($node), $node)
};

First of all I cannot iterate over $user_xml/user. If I try to iterate over $user_xml I get the exception

arg1 is not of type node()

But maybe its the wrong approach anyway?

Does anybody maybe have sample code how to do this?

1
If you aren't going to use the standar XQuery Update, nor the standar XQuery to get an updated result, but you're going to use some MarkLogic's extension functions, then this is an xqueryengines questionuser357812

1 Answers

5
votes

I have to answer it myself:

declare function update-user (
$username as xs:string,
$user_xml as node()) as empty-sequence()
{
let $uri := user-uri($username)
return
    for $node in $user_xml/*
    let $target := fn:doc($uri)/user/*[fn:name() = fn:name($node)]
    return
        if($target) then
            xdmp:node-replace($target, $node)
        else
            xdmp:node-insert-child(fn:doc($uri)/user, $node)
};

but maybe someone has a better solution to /user/*[fn:name() = fn:name($node)]?