<?xml version="1.0" encoding="ISO-8859-1"?>
<article version="5.0" xmlns="http://docbook.org/ns/docbook">
  <title>XQuery Update for the impatient</title>

  <subtitle>A quick introduction to the XQuery Update Facility</subtitle>

  <info>
    <author>
      <orgname>Xavier Franc</orgname>
    </author>

    <pubdate>October 18, 2025</pubdate>

    <legalnotice>
      <para>This article is published under the <link
      xlink:href="http://creativecommons.org/licenses/by-sa/3.0/"
      xmlns:xlink="http://www.w3.org/1999/xlink">Creative Commons
      "Attribution-Share Alike"</link> license.</para>
    </legalnotice>
  </info>

  <para>The XQuery Update Facility is a relatively small extension of the
  XQuery language which provides convenient means of modifying XML documents
  or data. As of March 14, 2008, the <link
  xlink:href="http://www.w3.org/TR/xquery-update-10/"
  xmlns:xlink="http://www.w3.org/1999/xlink">XQuery Update Facility
  specification</link> has become a "Candidate Recommendation", which means it
  is now pretty stable.</para>

  <para>Why an update facility in XML Query? The answer seems obvious, yet
  after all the XQuery language itself - or its cousin XSLT2 - is powerful
  enough to write any transformation of an XML tree. Therefore a simple
  "store" or "put" function, applied to the result of such transformation,
  could seem sufficient to achieve any kind of database update operation.
  Well, perhaps. In practice this would be neither very natural, convenient,
  nor very efficient (such an approach requires storing back the whole
  document and makes optimizing very difficult). So as we will see the little
  complexity added by XQuery Update seems quite worth the effort.</para>

  <para>This tutorial attempts to give a quick yet comprehensive practical
  introduction to the XQuery Update extension, while highlighting some of its
  peculiarities.</para>

  <formalpara>
    <title>Prerequisites:</title>

    <para>the reader is presumed to have some acquaintance with XML Query and
    its <glossterm>Data Model</glossterm> (the abstract representation of XML
    data, involving <glossterm>nodes</glossterm> of six types: document,
    element, attribute, text, comment, processing-instruction).</para>
  </formalpara>

  <section>
    <title>Basics</title>

    <section>
      <title>The update primitives</title>

      <para>The XQuery Update Facility (abbreviated as <acronym>XQUF</acronym>
      hereafter) provides five basic operations acting upon XML
      <glossterm>nodes</glossterm>:</para>

      <itemizedlist>
        <listitem>
          <para><command>insert</command> one or several nodes
          inside/after/before a specified node</para>
        </listitem>

        <listitem>
          <para><command>delete</command> one or several nodes</para>
        </listitem>

        <listitem>
          <para><command>replace</command> a node (and all its descendants if
          it is an element) by a sequence of nodes.</para>
        </listitem>

        <listitem>
          <para><command>replace</command> the <command>contents</command>
          (children) of a node with a sequence of nodes, or the
          <command>value</command> of a node with a string value.</para>
        </listitem>

        <listitem>
          <para><command>rename</command> a node (applicable to elements,
          attributes and processing instructions) without affecting its
          contents or attributes.</para>
        </listitem>
      </itemizedlist>

      <para>These primitives are detailed hereafter.</para>
    </section>

    <section>
      <title>How do the update primitives combine with the base
      language?</title>

      <para>Typically, we use some plain query to select the node(s) we want
      to update, then we apply update operations on those nodes. This is
      similar to the SQL <emphasis role="bold"><code>UPDATE ... WHERE
      ...</code></emphasis> instruction.</para>

      <para>Example 1: in a document <filename>doc.xml</filename>, rename as
      <literal>SECTION_TITLE</literal> all <literal>TITLE</literal> elements
      children of a <literal>SECTION</literal>:</para>

      <programlisting>for $title in doc("doc.xml")//SECTION/TITLE   (: selection :)
return rename node $title as SECTION_TITLE    (: update :)</programlisting>

      <para>Example 2: for all <literal>ITEM</literal> elements which have an
      attribute Id, replace that attribute with a child <literal>NID</literal>
      in first position:</para>

      <programlisting>for $idattr in doc("data.xml")//ITEM/@Id     (: selection :)
return (            
   delete node $idattr,                      (: update 1 :)
   insert node &lt;NID&gt;{string($idattr)}&lt;/NID&gt;  (: update 2 :)
      as first into $idattr/..
)</programlisting>

      <para>With the latter script the following fragment</para>

      <programlisting>&lt;ITEM Id="id123"&gt;some content&lt;/ITEM&gt; </programlisting>

      <para>would be modified into:</para>

      <programlisting>&lt;ITEM&gt;&lt;NID&gt;id123&lt;/NID&gt;some content&lt;/ITEM&gt; </programlisting>

      <note>
        <para>In the latter example, it is completely irrelevant whether the
        <command>delete</command> is written after or before the
        <command>insert node</command>. This surprising property of XQUF is
        explained below.</para>
      </note>

      <para>There are some restrictions in the way the 5 updating operations
      can mix with the base XQuery language. XQUF makes a distinction between
      <glossterm>Updating Expressions</glossterm> (which encompass update
      primitives) and non-updating expressions. Updating Expressions cannot
      appear anywhere. This topic will be explained in more detail.</para>
    </section>

    <section>
      <title>Processing models</title>

      <para>There are two main ways of using the update primitives:</para>

      <orderedlist>
        <listitem>
          <para><bridgehead>Direct update of an XML
          database:</bridgehead></para>

          <para>In the examples above, nodes belonging to a database are
          selected then updated.</para>

          <note>
            <para>The XQUF notion of a database is very general: it means any
            collection of XML documents or well-formed fragments
            (trees).</para>
          </note>

          <para>XQuery Update does not define precisely the protocol by which
          updating operations are applied to a database. This is left to
          implementations. For example transaction and isolation issues are
          not addressed by the specifications.</para>

          <para>It is simply assumed that updates are applied to the database
          when the execution of a script completes. The language is designed
          in such a way that semantics of the "apply-updates" operation are
          precisely defined, yet as much space as possible is left for
          optimization by database implementations.</para>

          <para>Points to be noticed:</para>

          <itemizedlist>
            <listitem>
              <para><emphasis>Updates are not applied immediately as the
              updating expression executes</emphasis>. Instead they are
              accumulated into a "Pending Update List". At some point at the
              end of the execution, Pending Updates are applied all at once,
              and the database is updated atomically.</para>

              <para>A noticeable consequence is that <emphasis>updates are not
              visible during the script execution</emphasis>, but only after.
              This can be fairly off-putting for a developer. It also has a
              definite influence on programming style. We will see later
              examples of this effect and how to cope with it.</para>
            </listitem>

            <listitem>
              <para>The same expression can update several documents at once.
              The examples above could be applied to any collection of
              documents instead of the single document doc.xml.
              Example:</para>

              <programlisting>for $title in collection("/allbooks")//SECTION/TITLE 
return rename node $title as SECTION_TITLE</programlisting>
            </listitem>
          </itemizedlist>
        </listitem>

        <listitem>
          <para><bridgehead>Transforms without side effects:
          </bridgehead></para>

          <para>The XQUF has a supplementary operation called
          <glossterm>transform</glossterm> which updates a
          <emphasis>copy</emphasis> of an existing node, without modifying the
          original, and returns the transformed tree.</para>

          <para>The following example produces a transformed version of
          doc.xml without actually touching the original document:</para>

          <programlisting>copy $d := doc("doc.xml")
modify ( 
  for $t in $d//SECTION/TITLE
  return rename node $t as SECTION_TITLE
 )
return $d</programlisting>

          <para>Notice that <emphasis>within the modify clause</emphasis>,
          XQUF forbids modifying the <emphasis>original version</emphasis> of
          copied trees (here the document doc.xml itself); only the copied
          trees can be modified. The following expression would cause an
          error:</para>

          <programlisting>copy $d := doc("doc.xml")
modify ( 
  for $t in doc("doc.xml")//SECTION/TITLE (: *** wrong *** :)
  return rename node $t as SECTION_TITLE
 )
return $d</programlisting>
        </listitem>
      </orderedlist>
    </section>
  </section>

  <section>
    <title>Going deeper</title>

    <section>
      <title>Primitive operations revisited</title>

      <variablelist>
        <varlistentry>
          <term>delete nodes</term>

          <listitem>
            <para>Syntax:</para>

            <programlisting><emphasis role="bold">delete node</emphasis> <replaceable>location</replaceable></programlisting>

            <programlisting><emphasis role="bold">delete nodes</emphasis> <replaceable>location</replaceable></programlisting>

            <para>The expression <replaceable>location</replaceable>
            represents a sequence of nodes which are marked for deletion (the
            actual number of nodes does not need to match the keyword
            <emphasis role="bold">node</emphasis> or <emphasis
            role="bold">nodes</emphasis>).</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>insert nodes</term>

          <listitem>
            <para>Syntax:</para>

            <programlisting><emphasis role="bold">insert (node|nodes)</emphasis> <replaceable>items</replaceable> <emphasis
                role="bold">into</emphasis> <replaceable>location</replaceable></programlisting>

            <programlisting><emphasis role="bold">insert (node|nodes)</emphasis> <replaceable>items</replaceable> <emphasis
                role="bold">as first into</emphasis> <replaceable>location</replaceable></programlisting>

            <programlisting><emphasis role="bold">insert (node|nodes)</emphasis> <replaceable>items</replaceable> <emphasis
                role="bold">as last into</emphasis> <replaceable>location</replaceable></programlisting>

            <programlisting><emphasis role="bold">insert (node|nodes)</emphasis> <replaceable>items</replaceable> <emphasis
                role="bold">before</emphasis> <replaceable>location</replaceable></programlisting>

            <programlisting><emphasis role="bold">insert (node|nodes)</emphasis> <replaceable>items</replaceable> <emphasis
                role="bold">after</emphasis> <replaceable>location</replaceable></programlisting>

            <para>The expression <replaceable>location</replaceable> must
            point to a single target node.</para>

            <para>The expression <replaceable>items</replaceable> must yield a
            sequence of items to insert relatively to the target node.</para>

            <para>Notice that even though the keyword <emphasis
            role="bold">node</emphasis> or <emphasis
            role="bold">nodes</emphasis> is used, the inserted items can be
            non-node items. What happens actually is that the <emphasis>string
            values</emphasis> of non-node items are concatenated to form text
            nodes.</para>

            <itemizedlist>
              <listitem>
                <para>If either form of <command>into</command> is used, then
                the target node must be an element or a document. The items to
                insert are treated exactly as the contents of an element
                constructor.</para>

                <para>For example if <varname>$target</varname> points to an
                empty element <literal>&lt;CONT/&gt;</literal>,</para>

                <programlisting>insert nodes (attribute A { 2.1 }, &lt;child1/&gt;, "text", 1 to 3) 
into $target</programlisting>

                <para>yields:</para>

                <programlisting>&lt;CONT A="2.1"&gt;&lt;child1/&gt;text 1 2 3&lt;/CONT&gt;</programlisting>

                <para>Therefore the same rules as in constructors apply: item
                order is preserved, a space is inserted between consecutive
                non-node items, inserted nodes are copied first, attribute
                nodes are not allowed after other item types, etc.</para>
              </listitem>

              <listitem>
                <para>When the keywords <command>as first</command> (resp.
                <command>as last</command>) are used, the items are inserted
                before (resp. after) any existing children of the
                element.</para>

                <para>For example if <varname>$target</varname> points to an
                element
                <literal>&lt;parent&gt;&lt;kid&gt;&lt;/parent&gt;</literal></para>

                <programlisting>insert node &lt;elder/&gt; as first into $target</programlisting>

                <para>yields:</para>

                <programlisting>&lt;parent&gt;&lt;elder/&gt;&lt;kid&gt;&lt;/parent&gt;</programlisting>

                <para>When the only keyword <command>into</command> is used,
                the resulting position is implementation dependent. It is only
                guaranteed that <command>as first into</command> and
                <command>as last into</command> have priority over
                <command>into</command>.</para>
              </listitem>

              <listitem>
                <para>If <command>before</command> or <command>after</command>
                are used, any node type is allowed for the target node.</para>
              </listitem>

              <listitem>
                <para>Attributes are a special case: regardless of the
                <command>before</command> or <command>after</command> keyword
                used, attributes are always inserted <command>into</command>
                the <emphasis>parent element</emphasis> of the target. The
                order of inserted attributes is unspecified. Name conflicts
                can generate errors.</para>
              </listitem>
            </itemizedlist>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>replace node</term>

          <listitem>
            <para>Syntax:</para>

            <programlisting><emphasis role="bold">replace node</emphasis> <replaceable>location</replaceable> <emphasis
                role="bold">with</emphasis> <replaceable>items</replaceable></programlisting>

            <para>The expression <replaceable>location</replaceable> must
            point to a single target node.</para>

            <para>The expression <replaceable>items</replaceable> must yield a
            sequence of items that will replace the target node.</para>

            <itemizedlist>
              <listitem>
                <para>Except for <classname>document</classname> and
                <classname>attribute</classname> node types, the target node
                can be replaced by any sequence of items. The replacing items
                are treated exactly as the contents of an element/document
                constructor.</para>

                <para>For example if <varname>$target</varname> points to an
                element <literal>&lt;P&gt;&lt;kid/&gt;some
                text&lt;/P&gt;</literal>,</para>

                <programlisting>replace node $target/kid with "here is" </programlisting>

                <para>yields:</para>

                <programlisting><literal>&lt;P&gt;here is some text&lt;/P&gt;</literal></programlisting>
              </listitem>

              <listitem>
                <para>Attributes are a special case: they can only be replaced
                by an attribute node. Name conflicts can generate
                errors.</para>
              </listitem>
            </itemizedlist>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>replace value of node</term>

          <listitem>
            <para>Syntax:</para>

            <programlisting><emphasis role="bold">replace value of node</emphasis> <replaceable>location</replaceable> <emphasis
                role="bold">with</emphasis> <replaceable>items</replaceable></programlisting>

            <para>Here the identity of the target node is preserved. Only its
            value or contents (for an element or a document) is
            replaced.</para>

            <itemizedlist>
              <listitem>
                <para>If the target is an element or a document node, then all
                its former children are removed and replaced. The replacing
                items are treated exactly as the contents of a text
                constructor (so all node items are replaced by their
                string-value).</para>

                <para>For example if <varname>$target</varname> points to an
                element <literal>&lt;P&gt;&lt;kid/&gt;some
                text&lt;/P&gt;</literal>,</para>

                <programlisting>replace value of node $target with (&lt;text&gt;let's count: &lt;/text&gt;, 1 to 3, "...") </programlisting>

                <para>yields:</para>

                <programlisting><literal>&lt;P&gt;let's count: 1 2 3 ...&lt;/P&gt;</literal></programlisting>

                <para>So the element contents are replaced by a <emphasis>text
                node</emphasis> whose value is the concatenation of the string
                values of replacing items.</para>
              </listitem>

              <listitem>
                <para>If the target node is a leaf node (attribute, text,
                comment, processing-instruction) then its string value is
                replaced by the concatenation of the string values of
                replacing items.</para>

                <para>For example if <varname>$target</varname> points to an
                element <literal>&lt;P order="old"&gt;some
                text&lt;/P&gt;</literal>,</para>

                <programlisting>replace value of node $target/@order with (1 to 3, &lt;ell&gt;...&lt;/ell&gt;) </programlisting>

                <para>yields:</para>

                <programlisting><literal>&lt;P order="1 2 3..."&gt;some text&lt;/P&gt;</literal></programlisting>
              </listitem>
            </itemizedlist>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>rename node</term>

          <listitem>
            <para>Syntax:</para>

            <programlisting><emphasis role="bold">rename node</emphasis> <replaceable>location</replaceable> <emphasis
                role="bold">as</emphasis> <replaceable>name-expression</replaceable></programlisting>

            <para>The expression <replaceable>location</replaceable> must
            point to a single target element, attribute or
            processing-instruction.</para>

            <para>The expression <replaceable>name-expression</replaceable>
            must yield a single QName or string item.</para>

            <para>For example if <varname>$target</varname> points to an
            element <literal>&lt;CONT A="a"&gt;some
            text&lt;/CONT&gt;</literal></para>

            <programlisting>rename node $target as qName("some.namespace", "CONTAINER"),
rename node $target/A as "NEWA"</programlisting>

            <para>yields:</para>

            <programlisting>&lt;ns1:CONTAINER NEWA="a" xmlns:ns1="some.namespace"&gt;some text&lt;/ns1:CONTAINER&gt;</programlisting>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>transform</term>

          <listitem>
            <para>Syntax:</para>

            <programlisting><emphasis role="bold">copy</emphasis> <replaceable>$var</replaceable> := <replaceable>node</replaceable> [, <replaceable>$var2</replaceable> := <replaceable>node2</replaceable> ...] 
<emphasis role="bold">modify</emphasis> <replaceable>updating-expression </replaceable>
<emphasis role="bold">return</emphasis> <replaceable>expression</replaceable></programlisting>

            <para>Each <replaceable>node</replaceable> expression is copied
            (at least virtually) and bound to a variable.</para>

            <para>The <replaceable>updating-expression</replaceable> contains
            or invokes one or several update primitives. These primitives
            <emphasis>are allowed to act only upon the copied XML
            trees</emphasis>, pointed by the bound variables. Therefore the
            transform expression has no side effect.</para>

            <para>Before the <literal>return</literal> expression is
            evaluated, all updates are applied to the copied trees. Typically
            the <literal>return</literal> expression would be a bound
            variable, or a node constructor involving the bound variables, so
            it will yield the updated tree(s).</para>

            <para>For example if <varname>$target</varname> points to an
            element</para>

            <programlisting>copy $target := &lt;CONT id="s1"&gt;some text&lt;/CONT&gt;
modify (
   rename node $target as "SECTION",
   insert node &lt;TITLE&gt;The title&lt;/TITLE&gt; as first into $target
)
return element DOC { $target }</programlisting>

            <para>returns:</para>

            <programlisting>&lt;DOC&gt;&lt;SECTION id="s1"&gt;&lt;TITLE&gt;The title&lt;/TITLE&gt;some text&lt;/SECTION&gt;&lt;/DOC&gt;</programlisting>
          </listitem>
        </varlistentry>
      </variablelist>
    </section>

    <section>
      <title>The Problem of Invisible Updates</title>

      <para>The fact that updates are applied only at the end of a script
      execution has two consequences on programming, one disturbing, one
      pleasant:</para>

      <itemizedlist>
        <listitem>
          <para>The disturbing consequence is that you don't see your updates
          until the end, therefore you cannot build on your changes to make
          other changes.</para>

          <para>An example: suppose you have elements named PERSON. Inside a
          PERSON there can be a list of BID elements (representing bids made
          by this person), and you want the BID elements to be wrapped in a
          BIDS element. But initially the PERSON has no BIDS child.</para>

          <para>Initially:</para>

          <programlisting>&lt;PERSON id="p0234"&gt;
  &lt;NAME&gt;Joe&lt;/NAME&gt;
&lt;/PERSON&gt;</programlisting>

          <para>We want to insert <literal>&lt;BID
          id="b0012"&gt;data&lt;/BID&gt;</literal> to obtain:</para>

          <programlisting>&lt;PERSON id="p0234"&gt;
  &lt;NAME&gt;Joe&lt;/NAME&gt;
  &lt;BIDS&gt;
     &lt;BID id="b0012"&gt;data&lt;/BID&gt;
  &lt;BIDS&gt;
&lt;/PERSON&gt;</programlisting>

          <para>Classically, for example using the DOM, we would proceed in
          two steps:</para>

          <orderedlist>
            <listitem>
              <para>If there is no BIDS element inside PERSON, then create
              one</para>
            </listitem>

            <listitem>
              <para><emphasis>then</emphasis> insert the BID element inside
              the BIDS element</para>
            </listitem>
          </orderedlist>

          <para>In XQuery Update this would (incorrectly) be written like
          this:</para>

          <programlisting>declare updating function insert-bid($person, $bid)
{
  if(empty($person/BIDS))
    then insert node &lt;BIDS/&gt; into $person
    else (),
  insert node $bid as last into $person/BIDS
}</programlisting>

          <para><emphasis role="bold">Don't try that: it won't work!
          </emphasis>Why? Because the BIDS element will be created only at the
          very end, therefore the instruction
          <code>insert ... as last into $person/BIDS</code> will not find any
          node matching <code>$person/BIDS</code>, hence an execution
          error.</para>

          <para>So what is a correct way of doing ? We need a self-sufficient
          solution for each of the two cases:</para>

          <programlisting>declare updating function insert-bid($person, $bid)
{
 if(empty($person/BIDS))
   then insert node &lt;BIDS&gt;{$bids}&lt;/BIDS&gt; into $person
   else insert node $bid as last into $person/BIDS
}</programlisting>
        </listitem>

        <listitem>
          <para>The pleasant consequence is that the document(s) on which you
          are working are stable during execution of your script. You can rest
          assured that you are not sawing the branch you are sitting on. For
          example you can quietly write:</para>

          <programlisting>for $x in collection(...)//X
return delete node $x</programlisting>

          <para>This is perfectly predictable and won't stop prematurely. Or
          you can replicate an element after itself without risking looping
          forever:</para>

          <programlisting>for $x in collection(...)//X
return insert node $x after $x</programlisting>
        </listitem>
      </itemizedlist>
    </section>

    <section>
      <title>Mixing Updating and Non-updating Expressions</title>

      <para><emphasis>Updating Expressions</emphasis> are XQuery expressions
      that encompass the 5 updating primitives.</para>

      <para>There are rules about mixing Updating and Non-updating
      Expressions:</para>

      <itemizedlist>
        <listitem>
          <para>First of all, let us remember that Updating Expressions do not
          return any value. They simply add an update request to a list.
          Eventually the updates in the list are applied at the end of a
          script execution (or at the end of the <command>modify</command>
          clause in the case of the <command>transform</command>
          expression).</para>
        </listitem>

        <listitem>
          <para>Updating Expressions are therefore not allowed in places where
          a meaningful value is expected. For example the condition of a
          <command>if</command>, the right hand-side of a <command>let
          :=</command>, the <command>in</command> part of a
          <command>for</command> and so on.</para>
        </listitem>

        <listitem>
          <para>Mixing Updating and Non-updating Expressions is not allowed in
          a sequence (the comma operator). Though technically feasible, it
          would not make much sense to mix expressions that return a value and
          expressions that don't (remember that the sequence operator returns
          the concatenation of the sequences returned by its
          components).</para>

          <para>The <function>fn:error()</function> function and the empty
          sequence <constant>()</constant> are special as they can appear both
          in Updating and in non-updating expressions.</para>
        </listitem>

        <listitem>
          <para>In the same way, the branches of a <command>if</command> or a
          <command>typeswitch</command> must be consistent: both Updating or
          both Non-updating. If both branches are Updating then the
          <command>if</command> itself is considered Updating, and
          conversely.</para>
        </listitem>

        <listitem>
          <para>If the body of a function is an Updating Expression, then the
          function must be declared with the <command>updating</command>
          keyword. Example:</para>

          <programlisting>declare updating function insert-id($elem, $id-value) {
   insert node attribute id { $id-value } into $elem
}</programlisting>

          <para>A call to such a function is itself considered an Updating
          Expression. Logically enough, an updating function returns no value
          and therefore is not allowed to declare a return type.</para>
        </listitem>
      </itemizedlist>
    </section>

    <section>
      <title>Order and Conflicts</title>

      <para>Another consequence of the "Pending Updates" mechanism is that the
      order in which updates are specified is not important. In the following
      example you can without any issue delete the attribute <code>Id</code>
      (pointed by <code>$idattr</code>), and <emphasis>after</emphasis> use
      <code>$idattr/..</code> (the parent ITEM element) for inserting! Or you
      could insert first and delete after.</para>

      <programlisting>for $idattr in doc("data.xml")//ITEM/@Id   (: selection :)
return (               (: updates :)
   delete node $idattr,
   insert node &lt;NID&gt;{string($idattr)}&lt;/NID&gt; as first into $idattr/..
)</programlisting>

      <para>But because of that, some conflicting changes can produce
      unpredictable results. For example two <command>rename</command> of the
      same node are conflicting, because we do not know in which order they
      would be applied. Other ambiguous operations: two
      <command>replace</command> of the same node, two <command>replace
      value</command> (or contents) of the same node.</para>

      <para>The XQUF specifications take care of forbidding such ambiguous
      updates. An error is generated (during the apply-updates stage) when
      such a conflict is detected.</para>

      <para>A bit ironically, no error is generated for meaningless but non
      ambiguous conflicts, for example both renaming and deleting the same
      node (<command>delete node</command> has priority over other
      operations).</para>
    </section>
  </section>

  <section>
    <title>Conclusion</title>

    <para>The XQuery Update Facility is a powerful, convenient and elegant
    extension of the XQuery language, in spite of a few peculiarities that can
    be slightly off-putting for programmers.</para>

    <para>We are looking forward to its wide adoption as the language of
    choice for updating XML databases. At the time this tutorial was written,
    there were already a few implementations: <link
    xlink:href="http://monetdb.cwi.nl/"
    xmlns:xlink="http://www.w3.org/1999/xlink">Monet DB (CWI)</link>, <link
    xlink:href="http://www.xmlmind.com/qizx/qizx.html"
    xmlns:xlink="http://www.w3.org/1999/xlink">Qizx (XMLmind)</link>, <link
    xlink:href="http://www.oracle.com/database/berkeley-db/xml/index.html"
    xmlns:xlink="http://www.w3.org/1999/xlink">Oracle Berkeley DB XML
    (Oracle)</link>, <link xlink:href="http://xqilla.sourceforge.net/HomePage"
    xmlns:xlink="http://www.w3.org/1999/xlink">XQilla</link>.</para>
  </section>
</article>
