0
votes

In my function update-replace, I am trying to dynamically replace an XML node in one of my XML data source files in MarkLogic by calling xdmp:node-replace like below:

declare function update-lib:update-rec($doc as xs:string, $path as xs:string, $country as xs:string, $name as xs:string, $population as xs:integer, $latitude as xs:decimal, $longitude as xs:decimal) as document-node() {
    (: read lock acquired :)
    fn:doc($doc),

    xdmp:node-replace(fn:doc($doc)/$path,
        <city>
            <country>{$country}</country>
            <name>{$name}</name>
            <population>{$population}</population>
            <latitude>{$latitude}</latitude>
            <longitude>{$longitude}</longitude>
        </city>
    ),


    (: after the following statement, txn ends and locks released :)
    xdmp:commit()
};

The function takes 7 arguments with the 1st arg being path to the XML source file, the 2nd being path inside the XML file to the node to be updated and the rest corresponds to the child element values.

When I call xdmp:node-replace to update data, I encounter the following error:

500 Internal Server Error

XDMP-ARGTYPE: (err:XPTY0004) xdmp:node-replace("/cities/city[3961]", JPMiyoshi56958) -- arg1 is not of type node() ...

So I decided to have arg1 evaluated to ensure that node() gets passed as the 1st arg of node-replace:

xdmp:node-replace(xdmp:eval(fn:doc($doc)/$path),
    <city>
        <country>{$country}</country>
        <name>{$name}</name>
        <population>{$population}</population>
        <latitude>{$latitude}</latitude>
        <longitude>{$longitude}</longitude>
    </city>
),

Now I receive the below error instead:

XDMP-UPEXTNODES: xdmp:node-replace(fn:doc("/content/Users/Tako/Sites/MarkLogic/xml/worldcities/import/cities1000_02.xml")/cities/city[3961], JPMiyoshi56958) -- Cannot update external nodes ...

After a little googling, I've found this. It sounds like an issue with xdmp:eval and its context:

http://developer.marklogic.com/pipermail/general/2008-September/001753.html

I tried the workaround suggested here using fn:concat to have everything constructed as a string including xdmp:node-replace and evaluating the whole statement.

xdmp:eval(fn:concat('xdmp:node-replace(fn:doc("', $doc, '")', $path,
    ', ', '<city><country>',$country,'</country><name>',$name,'</name><population>',$population,'</population><latitude>',$latitude,'</latitude><longitude>',$longitude,'</longitude></city>', ')')),

The application sits and waits for a very long time before timing out when I tried this. 500 Internal Server Error

SVC-EXTIME: xdmp:node-replace(fn:doc("/content/Users/Tako/Sites/MarkLogic/xml/worldcities/import/cities1000_17.xml")/cities/city[3961], JPMiyoshi56958) -- Time limit exceeded ...

All I want to do is to dynamically reference the XML file and the nodes to be updated and update the node with the info passed in. I must be overlooking something very fundamental or doing this completely wrong.

Could someone please shed light on this?

1
Hoave you tried xdmp:unpath() with your first script, second argument argument - $path to evaluate a string as an XPath and return the corresponding node(s). You may found more information at docs.marklogic.com/xdmp:unpath - Navin Rawat
This actually worked as well. Thank you! - takoloco

1 Answers

6
votes

In your first solution you are applying a string value to each document node returned by fn:doc($doc). That way you only end up with the string value of $xpath itself. The second solution effectively takes the the value of $xpath too, and tries to evaluate that. That is likely to generate a lot of nodes that are potentially all being updated.

I am not entirely sure why you are getting XDMP-UPEXTNODES, and timeouts, but the following should do..

Replace:

fn:doc($doc)/$path

with:

xdmp:value(fn:concat("fn:doc($doc)", $path))

HTH!