ConceptioArchiveW3C TR
W3C TRopen access

xquery update 10 use cases

W3C · w3c_tr
W3C TR · Standards · License: Open Access
Open Source ↗
w3c, standard

XQuery Update Facility 1.0 Use Cases /**/ code { font-family: monospace; }

div.constraint, div.issue, div.note, div.notice { margin-left: 2em; }

div.issue p.title { margin-left: -2em; }

ol.enumar { list-style-type: decimal; } ol.enumla { list-style-type: lower-alpha; } ol.enumlr { list-style-type: lower-roman; } ol.enumua { list-style-type: upper-alpha; } ol.enumur { list-style-type: upper-roman; }

li p { margin-top: 0.3em; margin-bottom: 0.3em; }

sup small { font-style: italic; color: #8F8F8F; } div.exampleInner pre { margin-left: 1em; margin-top: 0em; margin-bottom: 0em} div.exampleOuter {border: 4px double gray; margin: 0em; padding: 0em} div.exampleInner { background-color: #d5dee3; border-top-width: 4px; border-top-style: double; border-top-color: #d3d3d3; border-bottom-width: 4px; border-bottom-style: double; border-bottom-color: #d3d3d3; padding: 4px; margin: 0em } div.exampleWrapper { margin: 4px } div.exampleHeader { font-weight: bold; margin: 4px}

div.issue { border-bottom-color: black; border-bottom-style: solid; border-bottom-width: 1pt; margin-bottom: 20pt; }

th.issue-toc-head { border-bottom-color: black; border-bottom-style: solid; border-bottom-width: 1pt; }

table.small { font-size: x-small; } a.judgment:visited, a.judgment:link { font-family: sans-serif; color: black; text-decoration: none } a.processing:visited, a.processing:link { color: black; text-decoration: none } a.env:visited, a.env:link { color: black; text-decoration: none } /**/ This version: http://www.w3.org/TR/2011/NOTE-xquery-update-10-use-cases-20110125/ Latest version: http://www.w3.org/TR/xquery-update-10-use-cases/ Previous version: http://www.w3.org/TR/2008/CR-xquery-update-10-use-cases-20080314/ Editors: Ioana Manolescu, INRIA <[email protected]> Jonathan Robie, Red Hat <[email protected]> Copyright W3C ® MIT ERCIM Keio liability trademark document use This document specifies usage scenarios for the XQuery Update Facility. 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 This is a Working Group Note Process Document XML Query Working Group XML Activity This document incorporates a number of use cases that guided the development of XQuery Update Facility 1.0 Please report errors in this document using W3C's public Bugzilla system http://www.w3.org/XML/2005/04/qt-bugzilla [email protected] http://lists.w3.org/Archives/Public/public-qt-comments/ Publication as a Working Group Note This document was produced by a group operating under the 5 February 2004 W3C Patent Policy public list of any patent disclosures Essential Claim(s) section 6 of the W3C Patent Policy 1 Use Cases for XQuery Updates Use Case "R" - Updating Relational Data Description Document Type Definition (DTD) Schema for users.xml Schema for items.xml Schema for bids.xml Input Data Updates and Results Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Use Case "Address Book" - synchronizing address book entries Input Data Q1 Use Case "SOAP" - processing messages Input Data Q1 Use Case "Namespaces" - moving elements from one namespace to another Description Schema for the grant application Input Data Q1 Use case "Parts" - modifying recursive documents Input data Q1 Q2 Q3 Q4 Q6 Use case "Nil" XML Schema Sample input data ("employees.xml") Q1 A Normative References Revision Log Changes in internal WD 28 Aug 2007 Publication The use cases listed below were created by the XML Query Working Group W3C XQuery Update Facility Requirements 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 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: <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="users"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="user_tuple"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="user_tuple"> <xs:complexType> <xs:sequence> <xs:element ref="userid"/> <xs:element ref="name"/> <xs:element minOccurs="0" ref="rating"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="userid" type="xs:string"/> <xs:element name="name" type="xs:string"/> <xs:element name="rating" type="xs:string"/> </xs:schema> <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="items"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="item_tuple"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="item_tuple"> <xs:complexType> <xs:sequence> <xs:element ref="itemno"/> <xs:element ref="description"/> <xs:element ref="offered_by"/> <xs:element minOccurs="0" ref="start_date"/> <xs:element minOccurs="0" ref="end_date"/> <xs:element minOccurs="0" ref="reserve_price"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="itemno" type="xs:string"/> <xs:element name="description" type="xs:string"/> <xs:element name="offered_by" type="xs:string"/> <xs:element name="start_date" type="xs:string"/> <xs:element name="end_date" type="xs:string"/> <xs:element name="reserve_price" type="xs:string"/> </xs:schema> <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="bids"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="bid_tuple"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="bid_tuple"> <xs:complexType> <xs:sequence> <xs:element ref="userid"/> <xs:element ref="itemno"/> <xs:element ref="bid"/> <xs:element ref="bid_date"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="userid" type="xs:string"/> <xs:element name="itemno" type="xs:string"/> <xs:element name="bid" type="xs:string"/> <xs:element name="bid_date" type="xs:string"/> </xs:schema> 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 ... ... Snip ... ... Snip ... The entire data set is represented by the following tables: 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 The underlying database system has the following referential integrity constraints: A foreign key on the BIDS table requires that BIDS.USERID contains a value that is found in USERS.USERID A foreign key on the BIDS table requires that BIDS.ITEMNO contains a value that is found in ITEMS.ITEMNO 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 ... 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 ... ... Snip ... 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 ... ... Snip ... ... Snip ... 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 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 ... 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 ... 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 ... 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 ... 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 ... 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 ... ... Snip ... 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 the XQuery Update Facility declare revalidation strict;

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 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 "items.xml". In this query, we assume that a referential integrity constraint in the underlying database system requires that no bid can 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: This update violates the previously-mentioned referential integrity constraint. Therefore, its execution raises a dynamic error (see Kinds of Errors Add a bid for Annabel Lee on item 1002, at a price 5 dollars below the current highest bid. A trigger in the underlying database ensures 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: This update causes the previously mentioned trigger to return an error. Therefore, its execution will raise a dynamic error (see Kinds of Errors 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 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. This section describes the data prior to synchronization. archive.xml <archived-agenda> <last-synch-time>2005-10-05T10:00</last-synch-time> <entry> <name>Benjamin</name> <contact>[email protected]</contact> </entry> <entry> <name>Dario</name> <contact>[email protected]</contact> </entry> <entry> <name>Anthony</name> <contact>[email protected]</contact> </entry> </archived-agenda> log.xml <log> </log> copy1.xml 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>[email protected]</contact> </entry> <entry> <name>Dario</name> <contact>[email protected]</contact> </entry> <entry> <name>Anthony</name> <contact>[email protected]</contact> </entry> </agenda-version> copy2.xml 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>[email protected]</contact> </entry> <entry> <name>Dario</name> <contact>[email protected]</contact> </entry> <entry> <name>Anthony</name> <contact>[email protected]</contact> </entry> </agenda-version> 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 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 copied from first modified version unchanged due to conflict log.xml <log> update failure details archived agenda version first modified version second modified version copy1.xml <agenda-version> <entry> <name>Benjamin</name> kept after synchronization kept after synchronization kept after synchronization failure copy2.xml <agenda-version> <entry> kept after synchronization value taken from the other modified version kept after synchronization failure This use case processes the message found in Example 1 of the [SOAP Version 1.2 Part 0:Primer] 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> 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> This use case shows how (parts of) the elements in a document may be moved from one namespace to another. 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. 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> 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> 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> This use case illustrates modifications to documents having a recursive structure. Each update in this use case applies on the following documents. In these examples, we assume each update is applied to a fresh copy of the original 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 "part-list.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> 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/> 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> 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) Note: Because this data is not covered by a schema, an implementation that supports static typing will raise an error for the comparison $p/@partid eq $child/@partof 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> 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: 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"] 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> 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. 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> <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> 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> XQuery 1.0: An XML Query Language (Second Edition) et. al. latest version XML Query Use Cases et. al. latest version XQuery Update Facility 1.0 Requirements latest version XQuery Update Facility 1.0 et. al. latest version World Wide Web Consortium. SOAP Version 1.2 Part 0: Primer http://www.w3.org/TR/2003/REC-soap12-part0-20030624/ 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. 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. 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).

Related documents

Record · ID 153187 · SHA-256 79a14591b929bf15
Conceptio Open Knowledge Archive — every document is proof-bundled with source, license, and retrieval metadata.