2
votes

I am creating a web-based database application with eXist-db. My wish is to save the data the user inserts in a formula created with XForms into the database. For that the whole data structure is saved in the variable $content I store in the database with an XQuery module like that:

declare
    %rest:PUT("{$content}")
    %rest:path("/items")
function ffdb:change-items($content as node()*) {
    let $data := <items>
            { $content/items/* }
        </items>

    let $stored := xmldb:store($config:app-root, "1234.xml", $data)

    return
        doesnotmatter:function()
};

In this example $content contains the following nodeset:

<items>
    <item1>A</item>
    <item2>B</item>
    <itemlist>
        <item3>C</item3>
    <itemlist/>
<items>

That works fine. My problem is now that I want to insert a node with the content 'D' in $content/items/itemlist before I store it into the database. The storing result should be:

<items>
    <item1>A</item>
    <item2>B</item>
    <itemlist>
        <item3>C</item3>
        <item3>D</item3>
    <itemlist/>
<items>

That seems to be more difficult as I thought. I tried to change the query a hundred times I think. When I try to insert a nodeset directly in the $content I get the message that XQuery update expressions can not be applied to in-memory nodes. When I try to insert the nodeset in $data after declaring it the data is stored but unfortunately without the nodeset.

I also installed the module from https://github.com/ryanjdew/XQuery-XML-Memory-Operations and then inserted this at the beginning:

let $content2 := mem:copy($content) !
    ( 
    mem:insert-child(., $content/items/itemlist, attribute new-attribute {"item3"}),
    mem:execute(.))

After that I inserted $content2 instead of $content while declaring $data. The message I get is the following:

org.exist.xquery.XPathException: mem-op:MIXEDSOURCES The nodes to change are coming from multiple sources [at line 249, column 3, source: /db/apps/myapp/modules/memoryoperations/memory-operations-pure-xquery.xqy]

Do not really know what to do. I also tried to load the document after storing it and insert the nodeset here so that I do not change in-memory data but that also does not work. The nodeset is not been inserted.

1
Which version of eXist?Joe Wicentowski
Please note, the sample XML you provided is not well-formed.Joe Wicentowski

1 Answers

1
votes

You're correct that eXist's XQuery Update facility does not support in-memory operations. Besides an identity transform (e.g., using XSLT or a recursive application of XQuery's typeswitch expression, the "pure xquery" version of Ryan J. Dew's library that you found is a viable option.

Assuming you've downloaded the https://github.com/ryanjdew/XQuery-XML-Memory-Operations repository, unzipped it, and uploaded the resulting folder to /db/apps, this code will produce the desired results that you described (I'm using eXist 3.1.0 and testing the code in eXide):

xquery version "3.1";

import module namespace mem-op="http://maxdewpoint.blogspot.com/memory-operations" at 
    "/db/apps/XQuery-XML-Memory-Operations-master/memory-operations-pure-xquery.xqy";

let $content := 
    <items>
        <item1>A</item1>
        <item2>B</item2>
        <itemlist>
            <item3>C</item3>
        </itemlist>
    </items>
let $copy := mem-op:copy($content)
let $insert := mem-op:insert-child($copy, $content/itemlist, element item3 {"D"})
return
    mem-op:execute($insert)

This returns:

<items>
    <item1>A</item1>
    <item2>B</item2>
    <itemlist>
        <item3>C</item3>
        <item3>D</item3>
    </itemlist>
</items>