W3C

XQuery Update Facility 1.0 Use Cases

W3C Candidate Recommendation 14 March 2008

This version:
http://www.w3.org/TR/2008/CR-xquery-update-10-use-cases-20080314/
Latest version:
http://www.w3.org/TR/xquery-update-10-use-cases/
Previous version:
http://www.w3.org/TR/2007/WD-xquery-update-10-use-cases-20070828/
Editors:
Ioana Manolescu, INRIA <ioana.manolescu@inria.fr>
Jonathan Robie, Red Hat <jonathan.robie@redhat.com>

Abstract

This document specifies usage scenarios for the XQuery Update Facility.

Status of this Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

W3C publishes a Candidate Recommendation, as described in the Process Document, to indicate that the document is believed to be stable and to encourage implementation by the developer community. The publication of this document constitutes a call for implementations of this specification.

This document has been developed by the W3C XML Query Working Group, which is part of the XML Activity. It will remain a Candidate Recommendation until at least 20 June 2008. The Working Group expects to eventually publish this document as a Working Group Note.

The XML Query Working Group intends to submit this document for consideration as a W3C Proposed Recommendation at the same time that XQuery Update Facility 1.0 is submitted for the same consideration.

Once the entrance criteria for Proposed Recommendation have been achieved, the Director will be requested to advance this document to Proposed Recommendation status. Working closely with the developer community, we expect to show evidence of implementations by approximately 31 July 2008.

The WG believes that this document, published on 14 March 2008, is sufficiently mature and stable that the development community can begin developing implementation experience and reporting on that experience.

No substantive changes have been made to this specification since its publication as a Last Call Working Draft.

Please report errors in this document using W3C's public Bugzilla system (instructions can be found at http://www.w3.org/XML/2005/04/qt-bugzilla). If access to that system is not feasible, you may send your comments to the W3C XSLT/XPath/XQuery public comments mailing list, public-qt-comments@w3.org. It will be very helpful if you include the string “[UPDUC]” in the subject line of your report, whether made in Bugzilla or in email. Each Bugzilla entry and email message should contain only one error report. Archives of the comments and responses are available at http://lists.w3.org/Archives/Public/public-qt-comments/.

Publication as a Candidate Recommendation does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

Table of Contents

1 Use Cases for XQuery Updates
    1.1 Use Case "R" - Updating Relational Data
        1.1.1 Description
        1.1.2 Document Type Definition (DTD)
            1.1.2.1 DTD for users.xml
            1.1.2.2 DTD for items.xml
            1.1.2.3 DTD for bids.xml
        1.1.3 Input Data
        1.1.4 Updates and Results
            1.1.4.1 Q1
            1.1.4.2 Q2
            1.1.4.3 Q3
            1.1.4.4 Q4
            1.1.4.5 Q5
            1.1.4.6 Q6
            1.1.4.7 Q7
            1.1.4.8 Q8
            1.1.4.9 Q9
    1.2 Use Case "Address Book" - synchronizing address book entries
        1.2.1 Input Data
        1.2.2 Q1
    1.3 Use Case "SOAP" - processing messages
        1.3.1 Input Data
        1.3.2 Q1
    1.4 Use Case "Namespaces" - moving elements from one namespace to another
        1.4.1 Description
        1.4.2 Schema for the grant application
        1.4.3 Input Data
        1.4.4 Q1
    1.5 Use case "Parts" - modifying recursive documents
        1.5.1 Input data
        1.5.2 Q1
        1.5.3 Q2
        1.5.4 Q3
        1.5.5 Q4
        1.5.6 Q6
    1.6 Use case "Nil"
        1.6.1 XML Schema
        1.6.2 Sample input data ("employees.xml")
        1.6.3 Q1

Appendices

A Normative References
B Revision Log (Non-Normative)
    B.1 Changes in internal WD
    B.2 28 Aug 2007 Publication


1 Use Cases for XQuery Updates

The use cases listed below were created by the XML Query Working Group to illustrate important applications for an XML update facility. Each use case is focused on a specific application area, and contains a Document Type Definition (DTD) and example input data. Each use case specifies a set of updates that might be applied to the input data, and the expected resulting value of the modified input for each update. Since the English description of each query is concise, the expected results form an important part of the definition of each update directive. These use cases are inspired by the W3C XQuery Update Facility Requirements document.

These use cases represent a snapshot of an ongoing work. Some important application areas and important operations are not yet adequately covered by a use case. The XML Query Working Group reserves the right to add, delete, or modify individual queries or whole use cases as the work progresses. The presence of a query in this set of use cases does not necessarily indicate that the query will be expressible in the XQuery Update Facility to be created by the XML Query Working Group.

1.1 Use Case "R" - Updating Relational Data

One important use of an XML update language will be to update data stored in relational databases. This use case describes a set of such possible updates.

1.1.1 Description

This use case is based on performing updates on the data used in Use Case "R" from the [XML Query Use Cases]. The DTD and sample data from this Use Case are copied below for convenience, and exactly match those found in the XQuery Use Cases.

The data represents a relational database used by an online auction. The auction maintains a USERS table containing information on registered users, each identified by a unique userid, who can either offer items for sale or bid on items. An ITEMS table lists items currently or recently for sale, with the userid of the user who offered each item. A BIDS table contains all bids on record, keyed by the userid of the bidder and the item number of the item to which the bid applies.

The three tables used by the online auction are below, with their column-names indicated in parentheses.

USERS ( USERID, NAME, RATING )
ITEMS ( ITEMNO, DESCRIPTION, OFFERED_BY, 
        START_DATE, END_DATE, RESERVE_PRICE ) 
BIDS ( USERID, ITEMNO, BID, BID_DATE )

1.1.2 Document Type Definition (DTD)

This use case is based on three separate input documents named users.xml, items.xml, and bids.xml. Each of the documents represents one of the tables in the relational database described above, using the following DTDs:

1.1.2.1 DTD for users.xml
                                            
<!ELEMENT users (user_tuple*)> 
<!ELEMENT user_tuple (userid, name, rating?)> 
<!ELEMENT userid (#PCDATA)> 
<!ELEMENT name (#PCDATA)> 
<!ELEMENT rating (#PCDATA)>
 
1.1.2.2 DTD for items.xml
                  
<!ELEMENT items (item_tuple*)>
<!ELEMENT item_tuple (itemno, description, offered_by, 
                      start_date?, end_date?, reserve_price?)> 
<!ELEMENT itemno (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ELEMENT offered_by (#PCDATA)>
<!ELEMENT start_date (#PCDATA)>
<!ELEMENT end_date (#PCDATA)>
<!ELEMENT reserve_price (#PCDATA)>
1.1.2.3 DTD for bids.xml
                      
<!ELEMENT bids (bid_tuple*)> 
<!ELEMENT bid_tuple (userid, itemno, bid, bid_date)> 
<!ELEMENT userid (#PCDATA)> 
<!ELEMENT itemno (#PCDATA)> 
<!ELEMENT bid (#PCDATA)>
<!ELEMENT bid_date (#PCDATA)>

                      

1.1.3 Input Data

The following data is an excerpt of the initial state for Q1. In this particular use case, each update begins with the state resulting from the prior update.

<items>
  <item_tuple>
    <itemno>1001</itemno>
    <description>Red Bicycle</description>
    <offered_by>U01</offered_by>
    <start_date>1999-01-05</start_date>
    <end_date>1999-01-20</end_date>
    <reserve_price>40</reserve_price>
  </item_tuple>
    ... Snip ... 
</items>
<users>
  <user_tuple>
    <userid>U01</userid>
    <name>Tom Jones</name>
    <rating>B</rating>
  </user_tuple>
    ... Snip ... 
</users>
<bids>
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1001</itemno> 
    <bid>35</bid> 
    <bid_date>1999-01-07</bid_date> 
    </bid_tuple> 
  <bid_tuple> 
    ... Snip ... 
</bids>
                    

The entire data set is represented by the following table:

USERS
USERID NAME RATING
U01 Tom Jones B
U02 Mary Doe A
U03 Dee Linquent D
U04 Roger Smith C
U05 Jack Sprat B
U06 Rip Van Winkle B
ITEMS
ITEMNO DESCRIPTION OFFERED_BY START_DATE END_DATE RESERVE_PRICE
1001 Red Bicycle U01 1999-01-05 1999-01-20 40
1002 Motorcycle U02 1999-02-11 1999-03-15 500
1003 Old Bicycle U02 1999-01-10 1999-02-20 25
1004 Tricycle U01 1999-02-25 1999-03-08 15
1005 Tennis Racket U03 1999-03-19 1999-04-30 20
1006 Helicopter U03 1999-05-05 1999-05-25 50000
1007 Racing Bicycle U04 1999-01-20 1999-02-20 200
1008 Broken Bicycle U01 1999-02-05 1999-03-06 25
BIDS
USERID ITEMNO BID BID_DATE
U02 1001 35 1999-01-07
U04 1001 40 1999-01-08
U02 1001 45 1999-01-11
U04 1001 50 1999-01-13
U02 1001 55 1999-01-15
U01 1002 400 1999-02-14
U02 1002 600 1999-02-16
U03 1002 800 1999-02-17
U04 1002 1000 1999-02-25
U02 1002 1200 1999-03-02
U04 1003 15 1999-01-22
U05 1003 20 1999-02-03
U01 1004 40 1999-03-05
U03 1007 175 1999-01-25
U05 1007 200 1999-02-08
U04 1007 225 1999-02-12

A referential integrity constraint in the underlying database system requires that no bid be placed on an item unless it exists in the database.

1.1.4 Updates and Results

1.1.4.1 Q1

Add a new user (with no rating) to the users.xml view.

Solution in the XQuery Update Facility:

insert nodes 
  <user_tuple>
    <userid>U07</userid>
    <name>Annabel Lee</name>
  </user_tuple>
into doc("users.xml")/users

Expected resulting content of users.xml:

<users>
  <user_tuple>
    <userid>U01</userid>
    <name>Tom Jones</name>
    <rating>B</rating>
  </user_tuple>
  <user_tuple>
    <userid>U02</userid>
    <name>Mary Doe</name>
    <rating>A</rating>
  </user_tuple>
    ... Snip ... 
<user_tuple>
   <userid>U06</userid>
   <name>Rip Van Winkle</name>
   <rating>B</rating>
  </user_tuple>
  <user_tuple>
    <userid>U07</userid>
    <name>Annabel Lee</name>
  </user_tuple>
</users>
                                                
1.1.4.2 Q2

Enter a bid for user Annabel Lee on February 1st, 1999 for 60 dollars on item 1001.

Solution in the XQuery Update Facility:

let $uid := 
doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid
return 
  insert nodes
    <bid_tuple> 
      <userid>{data($uid)}</userid> 
      <itemno>1001</itemno> 
      <bid>60</bid> 
      <bid_date>1999-02-01</bid_date> 
    </bid_tuple>
  into doc("bids.xml")/bids 

Expected resulting content of bids.xml:

<bids>
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1001</itemno> 
    <bid>35</bid> 
    <bid_date>1999-01-07</bid_date> 
  </bid_tuple> 
  <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1001</itemno> 
    <bid>40</bid> 
    <bid_date>1999-01-08</bid_date> 
  </bid_tuple>
  ... Snip ... 
  <bid_tuple> 
    <userid>U01</userid> 
    <itemno>1002</itemno> 
    <bid>400</bid> 
    <bid_date>1999-02-14</bid_date> 
  </bid_tuple> 
    ... Snip ... 
    <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1007</itemno> 
    <bid>225</bid> 
    <bid_date>1999-02-12</bid_date> 
  </bid_tuple> 
  <bid_tuple> 
    <userid>U07</userid> 
    <itemno>1001</itemno> 
    <bid>60</bid> 
    <bid_date>1999-02-01</bid_date> 
  </bid_tuple> 
</bids>
                                                
1.1.4.3 Q3

Insert a new bid for Annabel Lee on item 1002, adding 10% to the best bid received so far for this item.

Solution in the XQuery Update Facility:

let $uid := doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid
let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno=1002]/bid)
return 
  insert nodes 
    <bid_tuple> 
      <userid>{data($uid)}</userid> 
      <itemno>1002</itemno> 
      <bid>{$topbid*1.1}</bid> 
      <bid_date>1999-02-01</bid_date> 
    </bid_tuple>
  into doc("bids.xml")/bids

Expected resulting content of bids.xml:

<bids>
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1001</itemno> 
    <bid>35</bid> 
    <bid_date>1999-01-07</bid_date> 
  </bid_tuple> 
    ... Snip ... 
  <bid_tuple> 
    <userid>U01</userid> 
    <itemno>1002</itemno> 
    <bid>400</bid> 
    <bid_date>1999-02-14</bid_date> 
  </bid_tuple> 
    ... Snip ... 
   <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1007</itemno> 
    <bid>225</bid> 
    <bid_date>1999-02-12</bid_date> 
  </bid_tuple> 
    ... Snip ... 
  <bid_tuple> 
    <userid>U07</userid> 
    <itemno>1002</itemno> 
    <bid>1320</bid> 
    <bid_date>1999-03-05</bid_date> 
  </bid_tuple> 
</bids>
                                                

The best bid for item 1002 had been at 1200, thus Annabel's bid is at 1320.

1.1.4.4 Q4

Set Annabel Lee's rating to B.

Solution in the XQuery Update Facility:

let $user := doc("users.xml")/users/user_tuple[name="Annabel Lee"]
return 
  if ($user/rating)
    then replace value of node $user/rating with "B"
    else insert node <rating>B</rating> into $user

Expected resulting content of users.xml:

<users>
  <user_tuple>
    <userid>U01</userid>
    <name>Tom Jones</name>
    <rating>B</rating>
  </user_tuple>
  <user_tuple>
    <userid>U02</userid>
    <name>Mary Doe</name>
    <rating>A</rating>
  </user_tuple>
    ... Snip ... 
  <user_tuple>
   <userid>U06</userid>
   <name>Rip Van Winkle</name>
   <rating>B</rating>
  </user_tuple>
  <user_tuple>
    <userid>U07</userid>
    <name>Annabel Lee</name>
    <rating>B</rating>
  </user_tuple>
</users>
                                                
1.1.4.5 Q5

Place a bid for Annabel Lee on item 1007, adding 10% to the best bid received so far on that item, but only if the bid amount does not exceed a given limit. The first query illustrates the desired behavior if the limit is exceeded.

Solution in the XQuery Update Facility:

let $uid := doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid
let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno=1007]/bid)
where $topbid*1.1 <= 200
return 
  insert nodes 
    <bid_tuple> 
      <userid>{data($uid)}</userid> 
      <itemno>1007</itemno> 
      <bid>{$topbid*1.1}</bid> 
      <bid_date>1999-02-01</bid_date> 
    </bid_tuple>
  into doc("bids.xml")/bids

Expected resulting content of bids.xml:

<bids>
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1001</itemno> 
    <bid>35</bid> 
    <bid_date>1999-01-07</bid_date> 
  </bid_tuple> 
    ... Snip ... 
    <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1007</itemno> 
    <bid>225</bid> 
    <bid_date>1999-02-12</bid_date> 
  </bid_tuple> 
</bids>

In the above, adding 10% to the best bid on item 1007 would have required a bid of 237, which is more than the allowed limit of 200. Thus, the bids.xml document does not change.

Place a bid for Annabel Lee on item 1007, adding 10% to the best bid received so far on that item, but only if the bid amount does not exceed 500. This illustrates the behavior when the resulting value is within the limit.

Solution in the XQuery Update Facility:

let $uid := doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid
let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno=1007]/bid)
where $topbid*1.1 <= 500
return 
  insert nodes 
    <bid_tuple> 
      <userid>{data($uid)}</userid> 
      <itemno>1007</itemno> 
      <bid>{$topbid*1.1}</bid> 
      <bid_date>1999-02-01</bid_date> 
    </bid_tuple>
  into doc("bids.xml")/bids

Expected resulting content of bids.xml

<bids>
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1001</itemno> 
    <bid>35</bid> 
    <bid_date>1999-01-07</bid_date> 
  </bid_tuple> 
    ... Snip ... 
   <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1007</itemno> 
    <bid>225</bid> 
    <bid_date>1999-02-12</bid_date> 
  </bid_tuple> 
  <bid_tuple> 
    <userid>U07</userid> 
    <itemno>1007</itemno> 
    <bid>237</bid> 
    <bid_date>1999-04-01</bid_date> 
  </bid_tuple> 
</bids>
1.1.4.6 Q6

Erase user Dee Linquent and the corresponding associated items and bids.

Solution in the XQuery Update Facility:

let $user := doc("users.xml")/users/user_tuple[name="Dee Linquent"]
let $items := doc("items.xml")/items/item_tuple[offered_by=$user/userid]
let $bids := doc("bids.xml")/bids/bid_tuple[userid=$user/userid]
return (
  delete nodes $user,
  delete nodes $items,
  delete nodes $bids
)

An alternative solution is:

let $user := doc("users.xml")/users/user_tuple[name="Dee Linquent"]
let $items := doc("items.xml")/items/item_tuple[offered_by=$user/userid]
let $bids := doc("bids.xml")/bids/bid_tuple[userid=$user/userid]
return 
  delete nodes $user, $items, $bids

The two solutions above highlight the fact that a list of delete operations is equivalent to deleting the list of nodes obtained by concatenating the operands on which the deletes applied.

Expected resulting content of items.xml:

<items>
  <item_tuple>
    <itemno>1001</itemno>
    <description>Red Bicycle</description>
    <offered_by>U01</offered_by>
    <start_date>1999-01-05</start_date>
    <end_date>1999-01-20</end_date>
    <reserve_price>40</reserve_price>
  </item_tuple>
    ... Snip ... 
  <item_tuple>
    <itemno>1004</itemno>
    <description>Tricycle</description>
    <offered_by>U01</offered_by>
    <start_date>1999-02-25</start_date>
    <end_date>1999-03-08</end_date>
    <reserve_price>15</reserve_price>
  </item_tuple>
  <item_tuple>
    <itemno>1007</itemno>
    <description>Racing bicycle</description>
    <offered_by>U04</offered_by>
    <start_date>1999-01-20</start_date>
    <end_date>1999-02-20</end_date>
    <reserve_price>200</reserve_price>
  </item_tuple>
  <item_tuple>
    <itemno>1008</itemno>
    <description>Broken bicycle</description>
    <offered_by>U01</offered_by>
    <start_date>1999-02-05</start_date>
    <end_date>1999-03-06</end_date>
    <reserve_price>25</reserve_price>
  </item_tuple>
</items>

In the above, items 1005 and 1006, offered by user Dee Linquent, have been erased; item 1007 now directly follows item 1004. Notice that the whole subtrees rooted at the corresponding <item_tuple> elements have been erased.

Expected resulting content of users.xml:

<users>
  <user_tuple>
    <userid>U01</userid>
    <name>Tom Jones</name>
    <rating>B</rating>
  </user_tuple>
  <user_tuple>
    <userid>U02</userid>
    <name>Mary Doe</name>
    <rating>A</rating>
  </user_tuple>
   <user_tuple>
    <userid>U04</userid>
    <name>Roger Smith</name>
    <rating>C</rating>
  </user_tuple>
  ... Snip ... 
  <user_tuple>
   <userid>U06</userid>
   <name>Rip Van Winkle</name>
   <rating>B</rating>
  </user_tuple>
</users>

In the above, user Dee Linquent has been erased.

Expected resulting content of bids.xml:

<bids>
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1001</itemno> 
    <bid>35</bid> 
    <bid_date>1999-01-07</bid_date> 
  </bid_tuple> 
  <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1001</itemno> 
    <bid>40</bid> 
    <bid_date>1999-01-08</bid_date> 
  </bid_tuple> 
  ... Snip ... 
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1002</itemno> 
    <bid>600</bid> 
    <bid_date>1999-02-16</bid_date> 
  </bid_tuple> 
  <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1002</itemno> 
    <bid>1000</bid> 
    <bid_date>1999-02-25</bid_date> 
  </bid_tuple> 
  ... Snip ... 
  <bid_tuple> 
    <userid>U04</userid> 
    <itemno>1007</itemno> 
    <bid>225</bid> 
    <bid_date>1999-02-12</bid_date> 
  </bid_tuple> 
</bids>

No bids had been placed on items 1005 and 1006 offered by user Dee Linquent. However, Dee Linquent had placed a bid on item 1002; this bid has been erased.

1.1.4.7 Q7

Add the element <comment>This is a bargain !</comment> as the last child of the <item> element describing item 1002.

Solution in the XQuery Update Facility

insert nodes
  <comment>This is a bargain !</comment>
as last into doc("items.xml")/items/item_tuple[itemno=1002] 

Expected resulting content of items.xml: The same as the original contents.

The items.xml document is unchanged and an error is raised. This update can not be applied without rendering the document invalid with respect to its schema.

1.1.4.8 Q8

Place a bid for Annabel Lee on item 1010, which does not exist in "items.xml". A referential integrity constraint in the underlying database system requires that no bid be placed on an item unless it exists in the database.

Solution in XQuery:

let $uid := doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid
return 
  insert nodes
    <bid_tuple> 
      <userid>{data($uid)}</userid> 
      <itemno>1010</itemno> 
      <bid>60</bid> 
      <bid_date>2006-04-23</bid_date> 
    </bid_tuple>
  into doc("bids.xml")/bids 

Expected resulting content of bids.xml: the same as the original contents.

This update violates an application constraint. Therefore, its execution raises a dynamic error (see Kinds of Errors in the XQuery specification).

1.1.4.9 Q9

Add a bid for Annabel Lee on item 1002, at a price 5 dollars below the current highest bid. An auction application constraint imposes that a bid cannot be made at a lower price than the highest bid made so far on that item.

Solution in XQuery:

let $uid := doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid
let $topbid := max(doc("bids.xml")//bid_tuple[itemno=1002]/bid)
return 
  insert nodes
    <bid_tuple> 
      <userid>{data($uid)}</userid> 
      <itemno>1002</itemno> 
      <bid>{$topbid - 5.00}</bid> 
      <bid_date>2006-04-23</bid_date> 
    </bid_tuple>
  into doc("bids.xml")/bids 

Expected resulting content of bids.xml: the same as the original contents.

Like the previous one, this update violates an application constraint, therefore its execution will raise a dynamic error (see Kinds of Errors in the XQuery specification).

1.2 Use Case "Address Book" - synchronizing address book entries

In this scenario, an address book is synchronized among a central archive and two local copies. This scenario is inspired by the Unison file synchronizer. During synchronization, Address book entries with the same name element are considered to be the same entry. The order of entries is irrelevant. For simplicity, we assume that entries may be modified, but not inserted or deleted. When the two copies are synchronized, their state is saved into an archival version. Synchronization is performed as follows:

  • If an entry in one of the two copies is different from the archived one, but the other copy matches the archive, the modified copy is propagated to the archive and to the other copy.

  • If both copies differ from the archive, but they do not both modify the same element in the entry, or they modify the same element but the modified elements have the same value, then the changes from each copy are propagated to both the archive and the other copy.

  • If the copies have each modified the same entry, but modified it in different ways, a problem is reported in the log, and neither the archive nor the copies are changed. (For simplicity, we do not attempt to merge updates.)

The XQuery Update Facility is sufficient for the problem as scoped above. For more complex scenarios, the XQuery Scripting Extensions will simplify programming by allowing variable assignment and the ability to view the results of prior updates within a query.

1.2.1 Input Data

This section describes the data prior to synchronization.

archive.xml: The central archive, before synchronization.

<archived-agenda>
  <last-synch-time>2005-10-05T10:00</last-synch-time>
  <entry>
    <name>Benjamin</name>
    <contact>benjamin@inria.fr</contact>
  </entry>
  <entry>
    <name>Dario</name>
    <contact>dario@uni-pisa.it</contact>
  </entry>
  <entry>
    <name>Anthony</name>
    <contact>tony@uni-toulon.fr</contact>
  </entry>
</archived-agenda>

log.xml: The central log, before synchronization.

<log>
</log>

copy1.xml: The first modified copy of the address book.

In this copy, Benjamin's contact has changed from INRIA to University of Versailles, Dario has moved from University of Pisa to University of Paris Sud, and Anthony has moved from University of Toulon to the ENA.

<agenda-version>
  <entry>
    <name>Benjamin</name>
    <contact>benjamin@uni-versailles.fr</contact>
  </entry>
  <entry>
    <name>Dario</name>
    <contact>dario@uni-parissud.fr</contact>
  </entry>
  <entry>
    <name>Anthony</name>
    <contact>tony@ena.fr</contact>
  </entry>
</agenda-version>

copy2.xml: The second modified copy of the address book.

In this copy, Benjamin has also moved to University of Versailles, Dario has not moved, and Anthony has moved to the EHESS instead of the ENA:

<agenda-version>  
  <entry>
    <name>Benjamin</name>
    <contact>benjamin@uni-versailles.fr</contact>
  </entry>
  <entry>
    <name>Dario</name>
    <contact>dario@uni-pisa.it</contact>
  </entry>
  <entry>
    <name>Anthony</name>
    <contact>tony@ehess.fr</contact>
  </entry>
 </agenda-version>

1.2.2 Q1

Synchronize the three logs as described in the description of this use case.

Solution in the XQuery Update Facility:

for $a in doc("archive.xml")/archived-agenda/entry, 
    $v1 in doc("copy1.xml")/agenda-version/entry, 
    $v2 in doc("copy2.xml")/agenda-version/entry
where $a/name = $v1/name
  and $v1/name = $v2/name
return 
  if ($a/contact = $v1/contact and $v1/contact=$v2/contact)
  then ()
  else 
    if ($v1/contact = $v2/contact)
    then replace value of node $a/contact with $v1/contact
    else 
      if ($a/contact = $v1/contact)
      then (
            replace value of node $a/contact with $v2/contact,
            replace value of node $v1/contact with $v2/contact
      )
      else 
        if ($a/contact = $v2/contact)
        then (
            replace value of node $a/contact with $v1/contact,
            replace value of node $v2/contact with $v1/contact
        )
        else (
          insert node
            <fail>
               <arch>{ $a }</arch>
               <v1>{ $v1 }</v1>
               <v2>{ $v2 }</v2>
            </fail>
          into doc("log.xml")/log
        )
,
replace value of node doc("archive.xml")/*/last-synch-time
        with current-dateTime()

Expected Results:

Expected results of the agenda synchronization: A synchronization of the two versions of the agenda made on April 23th, 2006, at noon, should have the following impact on the archive, versions, and log.

Note:

In the following XML results, the comments (shown in italic font) were not created by the update directives, and are not part of the result documents. They have been added to explain where each part of a result document comes from.

archive.xml

<archived-agenda>
  <last-synch-time>2006-04-23T12:00</last-synch-time>
  <entry>
    <name>Benjamin</name>
     copied from the modified entries 

    <contact>benjamin@uni-versailles.fr</contact>
  </entry>
  <entry>
    <name>Dario</name>
     copied from first modified version 

    <contact>dario@uni-parissud.fr</contact>
  </entry>
  <entry>
    <name>Anthony</name>
    unchanged due to conflict 

    <contact>tony@uni-toulon.fr</contact>
  </entry>
</archived-agenda>

log.xml

<log>
   update failure details 
  <fail>
     <arch>
        archived agenda version 

       <entry>
         <name>Anthony</name>
         <contact>tony@uni-toulon.fr</contact>
       </entry>
     </arch>
     <v1>
        first modified version 

       <entry>
         <name>Anthony</name>
         <contact>tony@ena.fr</contact>
       </entry>
     </v1>
     <v2>
        second modified version 

       <entry>
         <name>Anthony</name>
         <contact>tony@ehess.fr</contact>
       </entry>
     </v2>
  </fail>
</log>

copy1.xml

<agenda-version>
  <entry>
    <name>Benjamin</name>
     kept after synchronization 
 
   <contact>benjamin@uni-versailles.fr</contact>
  </entry>
  <entry>
     kept after synchronization 

    <name>Dario</name>
    <contact>dario@uni-parissud.fr</contact>
  </entry>
  <entry>
     kept after synchronization failure 

    <name>Anthony</name>
    <contact>tony@ena.fr</contact>
  </entry>
</agenda-version>

copy2.xml

<agenda-version>  
  <entry>
     kept after synchronization 

    <name>Benjamin</name>
    <contact>benjamin@uni-versailles.fr</contact>
  </entry>
  <entry>
     value taken from the other modified version 

    <name>Dario</name>
    <contact>dario@uni-parissud.fr</contact>
  </entry>
  <entry>
     kept after synchronization failure 

    <name>Anthony</name>
    <contact>tony@ehess.fr</contact>
  </entry>
</agenda-version>

1.3 Use Case "SOAP" - processing messages

This use case processes the message found in Example 1 of the [SOAP Version 1.2 Part 0:Primer] to produce the message found in Example 2. The original message is not modified, but the new message is a modified copy of the original.

1.3.1 Input Data

The input data is taken directly from Example 1 of the [SOAP Version 1.2 Part 0:Primer].

<?xml version='1.0' ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"> 
 <env:Header>
  <m:reservation 
     xmlns:m="http://travelcompany.example.org/reservation" 
     env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
     env:mustUnderstand="true">
   <m:reference>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d
   </m:reference>
   <m:dateAndTime>2001-11-29T13:20:00.000-05:00
   </m:dateAndTime>
  </m:reservation>
  <n:passenger 
    xmlns:n="http://mycompany.example.com/employees"
    env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
    env:mustUnderstand="true">
   <n:name>Åke Jógvan Øyvind</n:name>
  </n:passenger>
 </env:Header>
 <env:Body>
  <p:itinerary
    xmlns:p="http://travelcompany.example.org/reservation/travel">
   <p:departure>
     <p:departing>New York</p:departing>
     <p:arriving>Los Angeles</p:arriving>
     <p:departureDate>2001-12-14</p:departureDate>
     <p:departureTime>late afternoon</p:departureTime>
     <p:seatPreference>aisle</p:seatPreference>
   </p:departure>
   <p:return>
     <p:departing>Los Angeles</p:departing>
     <p:arriving>New York</p:arriving>
     <p:departureDate>2001-12-20</p:departureDate>
     <p:departureTime>mid-morning</p:departureTime>
     <p:seatPreference/>
   </p:return>
  </p:itinerary>
  <q:lodging
   xmlns:q="http://travelcompany.example.org/reservation/hotels">
   <q:preference>none</q:preference>
  </q:lodging>
 </env:Body>
</env:Envelope>

Moreover, we assume the dynamic context associates to "airports" the following sequence:

<AIRPORT><CITY>New York</CITY><CODE>JFK</CODE></AIRPORT>
<AIRPORT><CITY>New York</CITY><CODE>LGA</CODE></AIRPORT>
<AIRPORT><CITY>New York</CITY><CODE>EWR</CODE></AIRPORT>
<AIRPORT><CITY>Los Angeles</CITY><CODE>LAX</CODE></AIRPORT>
<AIRPORT><CITY>San Francisco</CITY><CODE>SFO</CODE></AIRPORT>

1.3.2 Q1

Check to see if the airports are unambiguously specified in the incoming message. Produce a SOAP response by transforming the incoming message, modifying the time and date to the current time, and replacing the body with a request to clarify which airport should be used for New York City.

Solution in the XQuery Update Facility:

declare namespace 
  env="http://www.w3.org/2003/05/soap-envelope";
declare namespace 
  m="http://travelcompany.example.org/reservation";
declare namespace 
  n="http://mycompany.example.com/employees";
declare namespace 
  p="http://travelcompany.example.org/reservation/travel";

(:  A clarification is needed only if there are no
 :  airports or more than one for a given city. If
 :  there is precisely one, there is no need to
 :  ask for information on that city.
 :)

declare function local:airportChoices($city as xs:string)
{
  let $airports := collection("airports")[CITY = $city]
  return
    if (count($airports) = 0)
    then 
       <error> No airports found for {$city}!</error>
    else if (count($airports) > 1) 
    then 
       <airportChoices>
        { 
          for $c in $airports/CODE
          return (string( $c ), " ")
        }
       </airportChoices>
    else ()
};

(:  Make sure that each airport is unambiguous. If there is
 :  more than one airport for a city, ask for clarification.
 :
 :  The primer only shows the error condition, so it is not
 :  clear what to do if there are no errors. Here, we simply
 :  return the airports in the itinerary.
 :)

declare function local:airports($in as element(env:Envelope))
{
    let $departureDeparting := 
      $in//p:departure/p:departing
    let $departureDepartingAirports := 
      collection("airports")[CITY = $departureDeparting]
    let $departureArriving := 
      $in//p:departure/p:arriving
    let $departureArrivingAirports := 
      collection("airports")[CITY = $departureArriving]
    let $returnDeparting := 
      $in//p:return/p:departing
    let $returnDepartingAirports := 
      collection("airports")[CITY = $returnDeparting]
    let $returnArriving := 
      $in//p:return/p:arriving
    let $returnArrivingAirports := 
      collection("airports")[CITY = $returnArriving]
    return
       if ( count($departureDepartingAirports)=0 or 
            count($departureDepartingAirports)>1 or 
            count($departureArrivingAirports)=0 or 
            count($departureArrivingAirports)>1 or 
            count($returnDepartingAirports)=0 or 
            count($returnDepartingAirports)>1 or 
            count($returnArrivingAirports)=0 or 
            count($returnArrivingAirports)>1 )
         then
          <p:itineraryClarification>
            <p:departure>
              <p:departing>
                { local:airportChoices($departureDeparting) }
              </p:departing>
              <p:arriving>
                { local:airportChoices($departureArriving) }
              </p:arriving> 
            </p:departure>
            <p:return>
              <p:departing>
                { local:airportChoices($returnDeparting) }
              </p:departing>
              <p:arriving>
                { local:airportChoices($returnArriving) }
              </p:arriving>
            </p:return>
          </p:itineraryClarification>
         else 
          <p:itinerary>
            <p:departure>
              <p:departing>{$departureDeparting}</p:departing>
              <p:arriving>{$departureArriving}</p:arriving>
            </p:departure>
            <p:return>
              <p:departing>{$returnDeparting}</p:departing>
              <p:arriving>{$returnArriving}</p:arriving>
            </p:return>
          </p:itinerary>
};

declare variable $msg external;

copy $out := $msg/env:Envelope
modify (
  replace value of node $out//m:dateAndTime 
     with fn:current-dateTime(),
  replace node $out//env:Body 
  with <env:Body>
        { local:airports($out) }
       </env:Body>
)
return $out

Expected Result (from [SOAP Version 1.2 Part 0:Primer]):


<env:Envelope 
   xmlns:env="http://www.w3.org/2003/05/soap-envelope"> 
 <env:Header>
  <m:reservation 
    xmlns:m="http://travelcompany.example.org/reservation" 
    env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
    env:mustUnderstand="true">
   <m:reference>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d
   </m:reference>
   <m:dateAndTime>2001-11-29T13:35:00.000-05:00
   </m:dateAndTime> 
  </m:reservation>
  <n:passenger xmlns:n="http://mycompany.example.com/employees"
    env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
    env:mustUnderstand="true">
   <n:name>Åke Jógvan Øyvind</n:name>
  </n:passenger>
 </env:Header>
 <env:Body>
  <p:itineraryClarification 
    xmlns:p="http://travelcompany.example.org/reservation/travel">
   <p:departure>
     <p:departing>
       <p:airportChoices>
          JFK LGA EWR 
       </p:airportChoices>
     </p:departing>
   </p:departure>
   <p:return>
     <p:arriving>
       <p:airportChoices>
         JFK LGA EWR 
       </p:airportChoices>
     </p:arriving>
   </p:return>  
  </p:itineraryClarification>
 </env:Body>
</env:Envelope>

1.4 Use Case "Namespaces" - moving elements from one namespace to another

This use case shows how (parts of) the elements in a document may be moved from one namespace to another.

1.4.1 Description

An agriculture company and an university research lab are making a joint proposal to the National Agricultural Research Agency. An initial proposal has been made by cut and paste out of snippets provided by the two partners. Before being submitted, the proposal has to be moved to the National Agricultural Research Agency (NARA) namespace.

1.4.2 Schema for the grant application

The grant application document must conform to the following schema:

<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
           targetNamespace="http://www.anr.fr/nara" 
           elementFormDefault="qualified">
 <xsd:element name='grant'>
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element ref='name'/>
    <xsd:element ref='lab' minOccurs='0' maxOccurs='unbounded'/>
   </xsd:sequence>
  </xsd:complexType>
 </xsd:element>

 <xsd:element name='lab'>
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element ref='address' minOccurs='0' maxOccurs='1'/>
    <xsd:choice minOccurs='0' maxOccurs='unbounded'>
     <xsd:element ref='researcher'/>
     <xsd:element ref='PhD'/>
     <xsd:element ref='engineer'/>
     <xsd:element ref='lab' minOccurs="0" maxOccurs="unbounded"/>
    </xsd:choice>
   </xsd:sequence>
   <xsd:attribute name='name' type='xsd:string' use='required'/>
  </xsd:complexType>
 </xsd:element>

 <xsd:element name='PhD'>
  <xsd:complexType>
   <xsd:attribute name='advisor' type='xsd:IDREF' use='required'/>
  </xsd:complexType>
 </xsd:element>

 <xsd:element name='researcher'>
  <xsd:complexType>
   <xsd:attribute name='rid' type='xsd:ID' use='required'/>
   <xsd:attribute name='name' type='xsd:string' use='required'/>
   <xsd:attribute name='position' type='xsd:string' use='required'/>
  </xsd:complexType>
 </xsd:element>

 <xsd:element name='engineer'>
  <xsd:complexType>
   <xsd:attribute name='name' type='xsd:string' use='required'/>
  </xsd:complexType>
 </xsd:element>
</xsd:schema>

1.4.3 Input Data

The initial draft produced by the participants, "grant.xml", has the following content. The use of namespaces reflects the cut-and-paste approach used to create it:

<?xml version='1.0' ?>
<grant xmlns:nara="http://www.anr.fr/nara"> 
  <nara:lab name="AgroPlus"> 
     <nara:address>Saclay, France</nara:address> 
     <nara:researcher rid="r1" name="Fred" 
       position="technical staff"/> 
     <nara:researcher rid="r2" name="Liz" 
       position="lab assistant" /> 
     <coop:PhD 
       xmlns:coop="http://www.gouv.fr/univ-industry-coop/" 
       name="Marie" advisor="r1"/> 
     <agro:lab xmlns:agro="http://www.agroplus.com" 
       name="Dairy Dept"> 
       <agro:engineer name="Marc"/> 
     </agro:lab> 
  </nara:lab> 
  <univ:lab xmlns:univ="http://www.education.gouv.fr" 
    name="Food Engineering Dept, Orsay U."> 
    <univ:address>Orsay, France</univ:address> 
    <univ:researcher rid="r3" name="Henry" 
      position="associate professor"/> 
    <univ:PhD name="Robert" advisor="r3"/> 
    <PhD name="Julia" advisor="r1"/> 
  </univ:lab> 
</grant>  

1.4.4 Q1

Move all elements into the NARA namespace ("http://www.anr.fr/nara").

Solution in the XQuery Update Facility:

                                        
declare namespace nara = "http://www.anr.fr/nara";

for $e in doc("grant.xml")//*
where not (namespace-uri($e) eq "http://www.anr.fr/nara")
return 
  rename node $e 
      as QName("http://www.anr.fr/nara", 
               concat("nara:",local-name($e)))

Expected Result:


<nara:grant xmlns:nara="http://www.anr.fr/nara">
 <nara:lab name="AgroPlus">
   <nara:address>Saclay, France</nara:address>
   <nara:researcher rid="r1" name="Fred" 
     position="technical staff"/>
   <nara:researcher rid="r2" name="Liz" 
     position="lab assistant" />
   <nara:PhD 
     xmlns:coop="http://www.gouv.fr/univ-industry-coop/"
     name="Marie" advisor="r1"/>
    <nara:lab name="Dairy Dept">
      <nara:engineer name="Marc"/>
   </nara:lab>
 </nara:lab>
 <nara:lab name="Food Engineering Dept, Orsay U.">
  <nara:address>Orsay, France</nara:address>
  <nara:researcher rid="r3" name="Henry" 
    position="associate professor"/>
  <nara:PhD name="Robert" advisor="r3"/>
  <nara:PhD name="Julia" advisor="r1"/>
 </nara:lab>
</nara:grant>

1.5 Use case "Parts" - modifying recursive documents

This use case illustrates modifications to documents having a recursive structure.

1.5.1 Input data

Each update in this use case applies on the following documents. Note that update effects are never cummulated, i.e. each update applies on the same state of the data.

Document "part-tree.xml":

<parttree>
    <part partid="0" name="car">
        <part partid="1" name="engine">
            <part partid="3" name="piston"/>
        </part>
        <part partid="2" name="door">
            <part partid="4" name="window"/>
            <part partid="5" name="lock"/>
        </part>
    </part>
    <part partid="10" name="skateboard">
        <part partid="11" name="board"/>
        <part partid="12" name="wheel"/>
    </part>
    <part partid="20" name="canoe"/>
</parttree>

Document "partlist.xml":

<?xml version="1.0" encoding="ISO-8859-1"?>
<partlist>
  <part partid="0" name="car"/>
  <part partid="1" partof="0" name="engine"/>
  <part partid="2" partof="0" name="door"/>
  <part partid="3" partof="1" name="piston"/>
  <part partid="4" partof="2" name="window"/>
  <part partid="5" partof="2" name="lock"/>
  <part partid="10" name="skateboard"/>
  <part partid="11" partof="10" name="board"/>
  <part partid="12" partof="10" name="wheel"/>
  <part partid="20" name="canoe"/>
</partlist>

1.5.2 Q1

Delete all parts in "part-tree.xml".

Solution in the XQuery Update Facility:

delete nodes doc("part-tree.xml")//part

Expected resulting document "part-tree.xml":

<parttree/>

1.5.3 Q2

Delete all parts belonging to a car in "part-tree.xml", leaving the car itself.

Solution in the XQuery Update Facility:

delete nodes doc("part-tree.xml")//part[@name="car"]//part

Expected resulting document "part-tree.xml":

<parttree>
    <part partid="0" name="car"/>
    <part partid="10" name="skateboard">
        <part partid="11" name="board"/>
        <part partid="12" name="wheel"/>
    </part>
    <part partid="20" name="canoe"/>
</parttree>

1.5.4 Q3

Delete all parts belonging to a car in "part-list.xml", leaving the car itself.

Solution 1 in the XQuery Update Facility (leveraging "part-tree.xml"):

for $pt in doc("part-tree.xml")//part[@name="car"]//part, 
    $pl in doc("part-list.xml")//part
where $pt/@partid eq $pl/@partid
return 
  delete nodes $pl

Solution 2 (using a recursive updating function):

declare updating function 
    local:delete-subtree($p as element(part))
  {
      for $child in doc("part-list.xml")//part
      where $p/@partid eq $child/@partof
      return (
        delete nodes $child,
        local:delete-subtree($child)
      )
  };

for $p in doc("part-list.xml")//part[@name="car"]
return 
  local:delete-subtree($p)

Expected Result:

<partlist>
  <part partid="0" name="car"/>
  <part partid="10" name="skateboard"/>
  <part partid="11" partof="10" name="board"/>
  <part partid="12" partof="10" name="wheel"/>
  <part partid="20" name="canoe"/>
</partlist>

1.5.5 Q4

Add a radio to the car in "part-tree.xml", using a part number that hasn't been taken.

Solution in the XQuery Update Facility:

let $next := max(doc("part-tree.xml")//@partid) + 1
  return
    insert nodes <part partid="{$next}" name="radio"/>
       into 
       doc("part-tree.xml")//part[@partid=0 and @name="car"]

Expected Result:

<parttree>
    <part partid="0" name="car">
        <part partid="21" name="radio"/>
        <part partid="1" name="engine">
            <part partid="3" name="piston"/>
        </part>
        <part partid="2" name="door">
            <part partid="4" name="window"/>
            <part partid="5" name="lock"/>
        </part>
    </part>
    <part partid="10" name="skateboard">
        <part partid="11" name="board"/>
        <part partid="12" name="wheel"/>
    </part>
    <part partid="20" name="canoe"/>
</parttree>

Note: The position of the new element with respect to its siblings is implementation-dependent. If position is significant, and the user wants to ensure the element appears last, for example, "as last" should be used, as in the following query:

let $next := max(doc("part-tree.xml")//@partid) + 1
  return
    insert nodes <part partid="{$next}" name="radio"/>
       as last
       into doc("part-tree.xml")//part[@partid=0 and @name="car"]

1.5.6 Q6

The head office has adopted a new numbering scheme. In "part-tree.xml", add 1000 to all part numbers for cars, 2000 to all part numbers for skateboards, and 3000 to all part numbers for canoes.

Solution in the XQuery Update Facility:

for $keyword at $i in ("car", "skateboard", "canoe"),
    $parent in doc("part-tree.xml")//part[@name=$keyword]
let $descendants := $parent//part
for $p in ($parent, $descendants)
return 
  replace value of node $p/@partid with $i*1000+$p/@partid

Expected result:

<parttree>
    <part partid="1000" name="car">
        <part partid="1021" name="radio"/>
        <part partid="1001" name="engine">
            <part partid="1003" name="piston"/>
        </part>
        <part partid="1002" name="door">
            <part partid="1004" name="window"/>
            <part partid="1005" name="lock"/>
        </part>
    </part>
    <part partid="2010" name="skateboard">
        <part partid="2011" name="board"/>
        <part partid="2012" name="wheel"/>
    </part>
    <part partid="3020" name="canoe"/>
</parttree>

1.6 Use case "Nil"

This use case demonstrates transform expressions which construct modified copies of some data, which must remain valid according to the original schema. In this use case, keeping the modified copy valid requires adding an xsi:nil attribute.

1.6.1 XML Schema

A employees data set is described by the following XML Schema:

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema 
  targetNamespace="http://www.example.com/employees"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="employees">
    <xsd:complexType>
      <xsd:element name="employee" minOccurs="0" 
        maxOccurs="unbounded">
        <xsd:complexType>
          <xsd:attribute name="mgr" type="xsd:boolean" 
          default="false"/>
          <xsd:attribute name="dept" type="xsd:string"/>
          <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:element name="salary" type="xsd:decimal" 
              nillable="true"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

1.6.2 Sample input data ("employees.xml")

<employees>
  <employee mgr="true" dept="Toys">
    <name>Smith</name>
    <salary>100000</salary>
  </employee>
  <employee dept="Toys">
    <name>Jones</name>
    <salary>60000</salary>
  </employee>
  <employee mgr="true" dept="Shoes">
    <name>Roberts</name>
    <salary>150000</salary>
  </employee>
</employees>

1.6.3 Q1

Return all managers, omitting their salaries for confidentiality reasons. The returned document must be valid according to its XML Schema, so the query adds an xsi:nil attribute with value "true" to the salary element.

Solution in the XQuery Update Facility:

for $e in doc("employees.xml")//employee
where $e/@manager = true()
return
   copy $emp := $e
   modify (
     replace value of node $emp/salary with "" ,
     insert nodes (attribute xsi:nil {"true"}) 
        into $emp/salary
   )
   return $emp

Expected result:

<employee mgr="true" dept="Toys">
  <name>Smith</name>
  <salary xsi:nil="true"/>
</employee>
<employee mgr="true" dept="Shoes">
  <name>Roberts</name>
  <salary xsi:nil="true"/>
</employee>

A Normative References

XQuery 1.0
World Wide Web Consortium. XQuery 1.0: An XML Query Language. W3C Working Draft, 03 Nov. 2005. See http://www.w3.org/TR/xquery/.
XML Query Use Cases
World Wide Web Consortium. XML Query Use Cases. W3C Working Draft, 15 September 2005. See http://www.w3.org/TR/2005/WD-xquery-use-cases-20050915/.
XQuery Update Facility Requirements
World Wide Web Consortium. XQuery Update Facility Requirements. W3C Working Draft, 3 June 2005. See http://www.w3.org/TR/2005/WD-xquery-update-requirements-20050603/.
XQuery Update Facility
World Wide Web Consortium. XQuery Update Facility. W3C Working Draft, 8 May 2006. See http://www.w3.org/TR/2006/WD-xqupdate-20060508/.
SOAP Version 1.2 Part 0:Primer
World Wide Web Consortium. SOAP Version 1.2 Part 0: Primer W3C Recommendation 24 June 2003. See http://www.w3.org/TR/2003/REC-soap12-part0-20030624/.

B Revision Log (Non-Normative)

This log records the substantive changes that have been made to this document since the Working Draft of 8 May 2006.. Minor editorial changes are not included in this log.

B.1 Changes in internal WD

  • Clarified that the "application constraint" in 1.1.4.8 Q8 is a database integrity constraint, and added the constraint to the description of the data, in response to http://www.w3.org/Bugs/Public/show_bug.cgi?id=3796#add_comment.

B.2 28 Aug 2007 Publication

  • Clarified that updates for Use Case "R" are cumulative (see http://www.w3.org/Bugs/Public/show_bug.cgi?id=3567#c1).

  • Fixed update conflict in Use Case "Address", and clarified that some things would be easier using updates together with the Scripting Extensions (see http://www.w3.org/Bugs/Public/show_bug.cgi?id=3578#c1).

  • Fixed several errors in Use Case "SOAP" (see http://www.w3.org/Bugs/Public/show_bug.cgi?id=3578#c3).

  • Fixed Use Case "R" Q4 so that it tests to see whether a rating already exists (see http://www.w3.org/Bugs/Public/show_bug.cgi?id=3578#c4).

  • Fixed Use Case "Parts" Q3, fixing several bugs, see (http://www.w3.org/Bugs/Public/show_bug.cgi?id=3578#c6).