Skip to main content

XML Updates

MonetDB/XQuery fully supports the W3C XQuery Update Facility (XQUF), except for the transform feature.

note:August 2007, W3C published a new and final call that makes some changes to the syntax (e.g. do insert became insert node). These changes are not supported yet in this version of MonetDB/XQuery.

Start the Mserver, open an interactive mclient -lx, and add the document from the Hello World example:

  > pf:add-doc("http://monetdb.cwi.nl/XQuery/files/HelloWorld.xml",
               "greetings.xml", "greetings.xml", 10)

Only by passing a fourth parameter percentage between 1 and 99 (free-space to accommodate inserts - a performance tuning setting) we added the document as a updatable collection to our database. Background information on the MonetDB/XQuery of updates can be found in the Reference Manual.

Insert As First/Last

  > do insert <start/> as first into doc("greetings.xml")/doc

Update commands do not return any result. But we can now re-inspect the document:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc><start/>
   <greet kind="informal">Hi </greet>
   <greet kind="casual">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  </doc>

We inserted a new element directly as first child after <doc> . The absence of free space between <doc> and <code> shows there is no other (text) node between them.

 
  > do insert <end/> as last into doc("greetings.xml")/doc

Now we inserted a new element as a last child after <doc>:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc><start/>
   <greet kind="informal">Hi </greet>
   <greet kind="casual">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  <end/></doc>

Delete Nodes

One can delete multiple nodes in one XQUF do delete command. Except for deletion, all update commands of the XQUF work on a single target node.

  > let $doc := doc("greetings.xml") return do delete ($doc//start, $doc//end)

Now the <start/> and <end/> are gone again.

Insert Before/After

We can also insert a new element before another element:

  > do insert <greet kind="formal">Good day</greet> 
    before doc("greetings.xml")//greet[1]

Note that now there is no text node between the first two greetings:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc>
   <greet kind="formal">Good day</greet><greet kind="informal">Hi </greet>
   <greet kind="casual">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  </doc>

This can be fixed with an extra insert after:

  > do insert text {"
   "} after doc("greetings.xml")//greet[1]

Alternatively, one could have inserted two nodes directly:

  > do insert (<greet kind="formal">Good day</greet>, text {"
   "}) before doc("greetings.xml")//greet[1]

In both cases, the result is:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc>
   <greet kind="formal">Good day</greet>
   <greet kind="informal">Hi </greet>
   <greet kind="casual">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  </doc>

Replace Node

An entire node can be replaced by one or more new nodes:

  > do replace doc("greetings.xml")//greet[1] 
    with <greet kind="polite">Pleased to meet you</greet>

resulting in:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc>
   <greet kind="polite">Pleased to meet you</greet>
   <greet kind="informal">Hi </greet>
   <greet kind="casual">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  </doc>

Replace Value

We can also replace the value of attributes and (text) nodes:

  > let $formal := doc("greetings.xml")//greet[1]
    return
    (do replace value of $formal/@kind with "impolite",
     do replace value of $formal with "Bugger Off")

so now our first greeting is rather impolite:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc>
   <greet kind="impolite">Bugger Off</greet>
   <greet kind="informal">Hi </greet>
   <greet kind="casual">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  </doc>

Rename Element

An element can also change name:

  > do rename doc("greetings.xml")//greet[1] into "insult"

which turns our greeting into an insult:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc>
   <insult kind="impolite">Bugger Off</insult>
   <greet kind="informal">Hi </greet>
   <greet kind="casual">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  </doc>

NOTE: MonetDB/XQuery uses the syntax:

do rename .. into ..

instead of:

do rename .. as ..

due to problems in the XQUF Draft.

Advanced Updates

XQUF updating statements can be combined in complex statements, nested in for-loops, and even wrapped in

updating functions

:

  > declare updating function foo($n as element(), $k as xs:integer) 
    { 
      if (count($n/@nr) = 0) 
      then do insert attribute nr { $k } into $n
      else do replace value of $n/@nr with $k
    };
    for $greet at $k in doc("greetings.xml")//greet 
    return foo($greet, $k)

The above query takes all greetings, and adds a unique ascending number attribute to them:

  > doc("greetings.xml")

  <?xml version="1.0" encoding="utf-8"?>
  <doc>
   <insult kind="impolite">Bugger Off</insult>
   <greet kind="informal" nr="1">Hi </greet>
   <greet kind="casual" nr="2">Hello </greet>
   <location kind="global">World</location>
   <location kind="local">Amsterdam</location>
  </doc>

Note that adding new attributes to an XML element is done in the XQUF using insert into , passing in an attribute node.