Copyright © 2006 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
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/.
This document has been produced by the XML Query Working Group (part of the XML Activity), following the procedures set out in the W3C Process Document. This is the first version of this document.
This is the First Public Working Draft for review by W3C members and other interested parties. Publication as a Working Draft 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 corresponds to the current XQuery Update Facility Working Draft. The queries in this document have been parsed using a parser generated from the same grammar used to create the documentation for the XQuery Update Facility. The use cases currently contained in this document may be changed in future versions - several use cases are already under development (including some suggested by the public), and the Working Group expects to continue adding use cases. The Working Group also reserves the right to decide not to support use cases currently shown in this document.
Public comments on this document and its open issues are invited. Comments on this document should be made in W3C's public Bugzilla system (instructions can be found at http://www.w3.org/XML/2005/04/qt-bugzilla). When entering comments, select the Product named "XPath / XQuery / XSLT", the Component named "Update Facility Use Cases", and the Version named "Working drafts". If access to that system is not feasible, you may send your comments to the W3C XSLT/XPath/XQuery mailing list, public-qt-comments@w3.org. It will be very helpful if you include the string [UPDUseCases] in the subject line of your comment, whether made in Bugzilla or in email. Each Bugzilla entry and email message should contain only one comment. Archives of the comments and responses are available at http://lists.w3.org/Archives/Public/public-qt-comments/.
As of this publication, the Working Group expects to eventually publish this document as a Working Group Note. It is not expected to become a W3C Recommendation, and therefore it has no associated W3C Patent Policy licensing obligations.
Per section 4 of the W3C Patent Policy, Working Group participants have 150 days from the title page date of this document to exclude essential claims from the W3C RF licensing requirements with respect to this document series. Exclusions are with respect to the exclusion reference document, defined by the W3C Patent Policy to be the latest version of a document in this series that is published no later than 90 days after the title page date of this document.
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.1.4.10 Q10
1.2 Use Case "Address Book" - Synchronizing address book entries
1.2.1 Input Data
1.2.2 Q1
1.3 Use Case "SOAP"
1.3.1 Input Data
1.3.2 Q1
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, specifying the expected result. 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.
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.
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 )
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:
<!ELEMENT users (user_tuple*)> <!ELEMENT user_tuple (userid, name, rating?)> <!ELEMENT userid (#PCDATA)> <!ELEMENT name (#PCDATA)> <!ELEMENT rating (#PCDATA)>
<!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)>
Here is an abbreviated set of data showing the XML format of the instances:
<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 !!! --> <users> <user_tuple> <userid>U01</userid> <name>Tom Jones</name> <rating>B</rating> </user_tuple> <!-- !!! Snip !!! --> <bids> <bid_tuple> <userid>U02</userid> <itemno>1001</itemno> <bid>35</bid> <bid_date>1999-01-07</bid_date> </bid_tuple> <bid_tuple> <!-- !!! Snip !!! -->
The entire data set is represented by the following table:
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 |
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 |
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 |
Add a new user (with no rating) to the users.xml view.
Solution in XQuery:
insert { <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>
Enter a bid for user Annabel Lee on February 1st, 1999 for 60 dollars on item 1001.
Solution in XQuery:
let $uid := doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid do insert { <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>
Modify the value of Annabel Lee's bid on item 1001, from 60 to 65 dollars.
Solution in XQuery:
let $user := doc("users.xml")/users/user_tuple[name="Annabel Lee" and bid="60" and bid_date="1999-02-01"] do replace value of {$user/bid} with 65
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>U07</userid> <itemno>1001</itemno> <bid>65</bid> <bid_date>1999-02-01</bid_date> </bid_tuple> <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> </bids>
Insert a new bid for Annabel Lee on item 1002, adding 10% to the best bid received so far for this item.
Solution in XQuery:
let $uid := doc("users.xml")/users/user_tuple[name="Annabel Lee"]/userid let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno=1002]/bid) do insert { <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.
Set Annabel Lee's rating to B.
Solution in XQuery:
let $user := doc("users.xml")/users/user_tuple[name="Annabel Lee"] do replace value of {$user/rating} with "B"
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>
Place a 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 XQuery:
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 do insert { <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 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 XQuery:
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 do insert { <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>
Erase user Dee Linquent and the corresponding associated items and bids.
Solution in XQuery:
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] do ( delete {$user}, delete {$items}, delete {$bids} )
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.
Add the element <comment>This is a bargain !</comment> as the last child of the <item> element describing item 1002.
Solution in XQuery
insert { <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.
Place a bid for Annabel Lee on item 1010, which does not exist in "bids.xml".
Solution in XQuery: No solution provided.
Expected resulting content of bids.xml: the same as the original contents.
This query was designed to explore referential integrity constraints. Unfortunately, with the current mapping, we can not express these constraints with a W3C XML Schema, since there are three different XML files, and no schema can span them. How do we account for such constraints, which may well be implemented in an underlying system? Do we treat them as system-defined behavior?
Add a bid for Annabel Lee on item 1002, at a price 5 dollars below the current highest bid.
Solution in XQuery: No solution provided.
Expected resulting content of bids.xml: the same as the original contents.
This raises difficulties similar to those seen in Q9. However, Q9 might be addressed by using a different mapping and a schema that spans the data, providing identity contraints. Q10 expresses constraints that can not be expressed in W3C XML Schema. How do we account for such constraints, which may well be implemented in an underlying system? Do we treat them as system-defined behavior?
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.)
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>
Synchronize the three logs as described in the description of this use case.
Solution in XQuery:
for $a in doc("archive.xml")/entry, $v1 in doc("copy1.xml")/entry, $v2 in doc("copy2.xml")/entry where $a/name = $v1/name and $v1/name = $v2/name do if ($a/contact = $v1/contact and $v1/contact=$v2/contact) then () else if ($v1/contact = $v2/contact) then replace value of {$a/contact} with $v1/contact else if ($a/contact = $v1/contact) then ( replace value of {$a/contact} with $v2/contact, replace value of {$v1/contact} with $v2/contact ) else if ($a/contact = $v2/contact) then ( replace value of {$a/contact} with $v1/contact, replace value of {$v2/contact} with $v1/contact ) else ( insert { <fail> <arch>{ $a }</arch> <v1>{ $v1 }</v1> <v2>{ $v2 }</v2> </fail> } as last into doc("log.xml") )
Expected Results:
Expected results of the agenda synchronization: A synchronization of the two versions of the agenda made on Nov. 9th, 2005, at noon, should have the following impact on the archive, versions, and log.
archive.xml
<archived-agenda> <last-synch-time>2005-11-09T12: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
Note:
In the following XML, the comments were not created by the query, but have been added to explain where each part comes from.
<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>
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.
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>
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")/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-value( $c ), " ") } </airportChoices> else () }; (: Make sure that each airport is unambiguous. If there is : more than once 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")/AIRPORTS[CITY = $departureDeparting] let $departureArriving := $in//p:departure/p:arriving let $departureArrivingAirports := collection("airports")/AIRPORTS[CITY = $departureArriving] let $returnDeparting := $in//p:return/p:departing let $returnDepartingAirports := collection("airports")/AIRPORTS[CITY = $returnDeparting] let $returnArriving := $in//p:return/p:arriving let $returnArrivingAirports := collection("airports")/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> { local:airportChoices($departureDeparting) } { local:airportChoices($departureArriving) } { local:airportChoices($returnDeparting) } { local:airportChoices($returnArriving) } </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> }; for $in in $msg/env:Envelope return transform copy $out := $in do ( replace value of {$out//m:dateAndTime} with fn:currentDateTime(), replace {$out//env:Body} with <env:Body> { local:airports($in) } </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>