Search code examples
xmlxqueryexist-db

In memory operations - updating the value of a node in eXist-db


I know that eXist-db does not support in-memory updating/replacing. I have tried any possible route I have managed to understand from documentation/other people's questions, etc. I simply want to be able to edit/add some text in a web-form which collects the values from an xml index, and send that text back to be stored in the index. I have a database (index) of people like:

<person xml:id="pe0005">
    <persName>
    <surname>Smith</surname>
    [...]
    </persName>
</person>
<person xml:id="pe0006">
    <persName>
    <surname>Abdul</surname>
    [...]
    </persName>
</person>
[...]

I have a function containing an HTML form in my app.xql:

declare function app:persdetailsEdit($node as node(), $model as map(*), $searchkey as xs:string?)

{let $forename := doc(myfile))//tei:listPerson/tei:person[@xml:id=$searchkey]/tei:persName/tei:forename
let $peid := doc(myfile))//tei:listPerson/tei:person[@xml:id=$searchkey]/@xml:id

return
<div> 
<form action="update.xql" method="POST">  

Last name:<br/>
<input type="text" name="surname" value="{$surname}"/>
[...]
<input type="submit" value="Submit"/>

</form>
</div>};

In my update.xql file (is there a way to put this code in app.xq? HTML complains that the content of 'action' must be a URI) I have something like

let $forename := request:get-parameter('forename', '')
let $peid := request:get-parameter('peid', '')
let $oldforename := doc(myfile)//tei:listPerson/tei:person[@xml:id=$peid]/tei:persName/tei:forename
[...]

which grabs the new value ($forename) I want to update in my .xml file, substituting the old value ($oldforename). So far so good. Now,

update value/replace $oldforename with $forename

is not possible (it's an in-memory operation). xmldb:update or xmldb:store are of no help, apparently. I have used ryanjdew's XQuery-XML-Memory-Operations-master to no avail - apparently it's not ideal for changing the text inside nodes. To me it sounds very strange that something so banal and simple turns out to be so difficult to achieve. I'm obviously missing something super-simple. Any help would be hugely appreciated.


Solution

  • If you are updating the contents of an XML file stored in eXist's database, this is not an "in-memory" operation; it is a database operation. You can simply use eXist's XQuery Update facility. For example, in the following query, we will create an in-memory node, store it to disk, and perform an update to the on-disk version, returning the original in-memory node and the updated on-disk node:

    xquery version "3.1";
    
    declare namespace tei="http://www.tei-c.org/ns/1.0";
    
    let $in-memory := 
        <listPerson xmlns="http://www.tei-c.org/ns/1.0">
            <person xml:id="p1">
                <persName>Wolfgang</persName>
            </person>
            <person xml:id="p2">
                <persName>Dannes Wessels</persName>
            </person>
        </listPerson>
    let $store := xmldb:store("/db", "listPerson.xml", $in-memory)
    let $on-disk := doc("/db/listPerson.xml")
    let $update := update value $on-disk//tei:person[@xml:id eq "p1"]/tei:persName with "Wolfgang Meier"
    return
        (
            $in-memory,
            $on-disk
        )
    

    This query returns two nodes:

    <listPerson xmlns="http://www.tei-c.org/ns/1.0">
        <person xml:id="p1">
            <persName>Wolfgang</persName>
        </person>
        <person xml:id="p2">
            <persName>Dannes Wessels</persName>
        </person>
    </listPerson>
    
    <listPerson xmlns="http://www.tei-c.org/ns/1.0">
        <person xml:id="p1">
            <persName>Wolfgang Meier</persName>
        </person>
        <person xml:id="p2">
            <persName>Dannes Wessels</persName>
        </person>
    </listPerson>
    

    So updating on-disk nodes is absolutely possible. If it's not working for you, please provide a revised, self-contained, working example. (Your code as shown contains some syntax errors; e.g., doc(myfile).)