XQuery Update: insert or replace depending if node exists not possible?

PetrV picture PetrV · Mar 17, 2011 · Viewed 23.7k times · Source

I am trying to build simple XML database (inside BaseX or eXist-db), but I have trouble figuring how to modify values in document :

content is simple as this for test :

<p>
    <pl>
        <id>6></id>
    </pl>
</p>

I am trying to build something like function which would insert element into <pl> if that element is not present or replace it if it is present. But XQuery is giving me troubles yet :

When I try it head-on with if-then-else logic :

if (exists(/p/pl[id=6]/name)=false)
then insert node <name>thenname</name> into /p/pl[id=6]
else replace value  of node /p/pl[id=6]/name with 'elsename'

I get error Error: [XUDY0027] Replace target must not be empty. Clearly I am confused, why the else part is evaluated in both cases, thus the error. When I empty out the else part :

if (exists(/p/pl[id=6]/name)=true)
    then insert node <name>thenname</name> into /p/pl[id=6]
    else <dummy/>

Then I get Error: [XUST0001] If expression: no updating expression allowed.

When I try through declaring updating function, even then it reports error :

declare namespace testa='test';

declare updating function testa:bid($a, $b)
{
if (exists(/p/pl[id=6]/name)=true)
    then insert node <name>thenname</name> into /p/pl[id=6]
    else <dummy/>
};

testa:bid(0,0)

Error: [XUST0001] If expression: no updating expression allowed.

I've got these errors from BaseX 6.5.1 package.

So how can I modify values in a simple fashion if possible ? If I call insert straight, the there could be multiple elements of same value. If I call replace it will fail when the node does not exist. If I delete the node before insert/replace then I could destroy sub-nodes which I don't want.

In most SQL databases, these are quite simple task (like MYSQL 'replace' command).

Answer

joewiz picture joewiz · Mar 18, 2011

@Qiqi: @Alejandro is right. Your if expression is incorrect XQuery syntax:

if (exists(/p/pl[id=6]/name))
then insert node <name>thenname</name> into /p/pl[id=6]
else replace value of node /p/pl[id=6]/name with 'elsename'

Note that eXist-db's XQuery Update functionality is currently an eXist-specific implementation, so in eXist (currently) 1.4.x and 1.5dev, you'll want:

if (exists(/p/pl[id=6]/name))
then update insert <name>thenname</name> into /p/pl[id=6]
else update value /p/pl[id=6]/name with 'elsename'

This eXist-specific XQuery Update syntax is documented on http://exist-db.org/update_ext.html. This syntax was developed before the W3C XQuery Update spec had reached its current state. The eXist team plans to make eXist fully compliant with the W3C spec soon, but in the meantime the docs above should help you achieve what you need to if you use eXist.

Note too that your example code contains a typo inside the pl and id elements. The valid XML version would be:

<p>
  <pl>
    <id>6</id>
  </pl>
</p>