1

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.

HBMCS
  • 686
  • 5
  • 25

1 Answers1

1

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).)

Joe Wicentowski
  • 5,159
  • 16
  • 26
  • 1
    Hey joewiz, thanks for your reply. Of course the `myfile` bit is made up and it's not a source of error in my code. I get the 'operation not possible because it's an in-memory operation' error from eXist-db. I'll check this tomorrow and report back. – HBMCS Feb 04 '18 at 00:30
  • PS: does this mean that, in my case, I have to `let $in-memory := myfile.xml` ? – HBMCS Feb 04 '18 at 00:46
  • Ps2: even doing `let $in-memory := Wolfgang Dannes Wessels ` I get a 'not well formed' error at the start of that line ( – HBMCS Feb 04 '18 at 01:41
  • 1
    Just taking out `let $in-memory` and `let $store` instructions solves the issue! Now the index file is updated indeed, that's great! What are the in-memory and store variables for? Do I need them? – HBMCS Feb 04 '18 at 02:11
  • 1
    Good to hear! No, my query was just code to demonstrate the principles of constructing in-memory nodes, storing them into the database, and updating nodes therein. I used let clauses to perform these discrete steps; I named the variables mnemonically. Since I cannot see the full code you are working with, I would guess that the problem was perhaps that you had not yet stored the document into the database before using XQuery Update on its nodes - or that you had some document in the database, but you were trying to use XQuery Update on a different set of nodes which were only in-memory. – Joe Wicentowski Feb 04 '18 at 03:52
  • That's what I was doind - in fact, as you can see from my original post, is was doing `update value $oldforename with $forename`, so that's the source of the issues I was having, I guess. Is there a way to put the update code inside app.xp and not in an external update.xq, that you know? The HTML code `
    – HBMCS Feb 04 '18 at 10:02
  • Sure, you can move the update function into app.xql, but then you would typically need to invoke the updating function from an HTML template, e.g., an HTML file that receives the post results. Either way you are creating a separate file. So you may be happier keeping update code in a separate xq file. It just depends on which method you prefer: HTML template (I.e., an HTML file that calls functions in templating-aware XQuery library modules) or an XQuery main module (i.e., a xq file that itself performs the work). – Joe Wicentowski Feb 04 '18 at 14:54
  • ...except it won't let me apply templating if I keep the code in a separate xq file (https://stackoverflow.com/questions/21042783/exist-db-include-html-template-in-xq-data/21049306#21049306). So, at this point, I moved the code into app.xql with the submit calling an external HTML, calling in turn {app:update}, and now I have templating working correctly! Thanks again, I've been trying to achieve this apparently simple thing for months. The world is a better place now. – HBMCS Feb 04 '18 at 17:43