Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
This document specifies goals, requirements and use cases for the XQuery Update Facility 3.0.
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 https://www.w3.org/TR/.
This document is governed by the 1 September 2015 W3C Process Document.
This is a Working Group Note as described in the Process Document. It was developed by the W3C XML Query Working Group, which is part of the XML Activity.
This document includes, for each requirement, a corresponding status, indicating the situation of the requirement in XQuery Update Facility 3.0 at the time that it was issued as a Working Group Note in January 2017.
Three status levels are used:
This indicates that the requirement, according to its original formulation, has been completely met. Optional clarificatory text may follow.
This indicates that the requirement has been partially met according to its original formulation. When this status is indicated, explanatory text is provided to better clarify the current scope of the requirement.
This indicates that the requirement, according to its original formulation, has not been met. If this is the case, explanatory text is provided.
This document also incorporates a number of Use Cases that assist the Working Groups in determining whether a candidate requirement is, in fact, a real requirement and illustrating various problems that XQuery Update Facility 3.0 is intended to address.
Please report errors in this document using W3C's public Bugzilla system (instructions can be found at https://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 “[UPD30req]” in the subject line of your report, whether made in Bugzilla or in email. Please use multiple Bugzilla entries (or, if necessary, multiple email messages) if you have more than one comment to make. Archives of the comments and responses are available at https://lists.w3.org/Archives/Public/public-qt-comments/.
Publication as a Working Group Note 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.
This document describes the requirements and use cases for the XQuery Update Facility 3.0. [XQuery 3.0: An XML Query Language] provides queries, but has no support for adding new values or changing existing values. The XML Query Working Group intends to add support for updates in a future version of XQuery. This document only contains requirements that have not been previously met by [XQuery Update Facility 1.0]
The following usage scenarios describe how the XQuery Update Facility 3.0 may be used in various environments, and represent a wide range of activities and needs that illustrate the problem space to be addressed. They are intended to be used as design cases during the development of the XQuery Update Facility 3.0, and should be reviewed when critical decisions are made. These usage scenarios should also prove useful in helping non-members of the XML Query Working Group understand the intent and goals of the project.
Modify XML in persistent XML stores, including native XML databases, XML files stored on a file system, or XML stored in SQL databases.
Modify XML messages to change status and add information created while processing the message.
Add new data to an existing XML document; for instance, add a new entry to a BLOG or a data log.
Perform updates on configuration files, user profiles, or administrative logs represented in XML.
Create a new copy of an XML document or subtree that differs from the original in the way specified by the update. For instance, updates could be used to modify a web message in order to add new information and change headers to reflect the modified status.
Modifying XML views of non-XML sources, such as an [SQL/XML] view of a SQL database.
The following key words are used throughout the document to specify the extent to which an item is a requirement for the work of the XML Query Working Group:
This word means that the item is an absolute requirement.
This word means that the item is an absolute prohibition.
This word means that there may exist valid reasons not to treat this item as a requirement, but the full implications should be understood and the case carefully weighed before discarding this item.
This word means that an item deserves attention, but further study is needed to determine whether the item should be treated as a requirement.
When the words MUST, SHOULD, or MAY are used in this technical sense, they occur as a hyperlink to these definitions. These words will also be used with their conventional English meaning, in which case there is no hyperlink. For instance, the phrase "the full implications should be understood" uses the word "should" in its conventional English sense, and therefore occurs without the hyperlink.
The XQuery Update Facility 3.0 MUST be backwards compatible with [XQuery Update Facility 1.0].
Status: this requirement has been met.
The XQuery Update Facility 3.0 MUST be defined on the [XQuery and XPath Data Model (XDM) 3.0].
Status: this requirement has been met.
Note:
The properties of a Data Model instance that can be modified by the XQuery Update Facility 3.0 are discussed in 3.4 XML Query Update Functionality.
The XQuery Update Facility 3.0 MUST be based on [XQuery 3.0: An XML Query Language]. The XQuery Update Facility 3.0 MUST use XQuery 3.0 to identify items to be updated. The XQuery Update Facility 3.0 MUST use XQuery 3.0 to specify items used in the updates.
Status: this requirement has been met.
The XQuery Update Facility 3.0 MAY support an explicit XML Schema validation operation that preserves node identity.
This requirement has not been met. A decision was made by the Working Group not to do this; however, it is possible to work around this by making a "null" update.
The XQuery Update Facility 3.0 MAY be compositional with respect to XQuery 3.0 expressions; that is, it may be possible to use an update wherever an XQuery 3.0 expression is used.
Status: this requirement has not been met. Updating expressions are limited to specific syntactic contexts.
The XQuery Update Facility 3.0 MUST be able to support expressions that return both a non-empty XDM instance and a non-empty pending update list.
Status: this requirement has been partially met; a non-empty XDM instance and a non-empty pending update list can be returned by expressions, but support for what can be done with such mixed results is limited.
In this section, the terms Atomicity, Consistency, Isolation, and Durability are taken from the ACID model of transaction characteristics for databases, which is described in [Transaction Processing Concepts and Techniques].
At the end of an outermost update operation (that is, an update operation invoked from the external environment), the data model MUST be consistent with respect to the constraints specified in the Data Model 3.0. In particular, all type annotations MUST be consistent with the content of the items they govern.
Status: this requirement has been met.
The XQuery Update Facility 3.0 MAY define additional levels of granularity at which Data Model 3.0 constraints are enforced.
Status: this requirement has not been met.
The XQuery Update Facility 3.0 MUST NOT preclude the means by which operations can be isolated from concurrent operations.
Status: this requirement has been met.
The XQuery Update Facility 3.0 MUST NOT preclude a means to control the durability of atomic operations and atomic execution units.
Status: this requirement has been met.
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 section 3 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 sample data from this Use Case is copied below for convenience, and exactly match the data found in the XQuery 1.0 Use Cases. Instead of DTDs, we describe this data with W3C XML Schemas.
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 schemas:
<?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 ... </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 tables:
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 |
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
Insert a new bid for Roger Smith on item 1002, adding 10% to the best bid received so far for this item, and report back what bid was just entered.
Solution in the XQuery Update Facility:
let $uid := doc("users.xml")/users/user_tuple[name = "Roger Smith"]/userid let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno = 1002]/bid) let $newbid := $topbid * 1.1 return ( insert nodes <bid_tuple> <userid>{ data($uid) }</userid> <itemno>1002</itemno> <bid>{ $newbid }</bid> <bid_date>1999-03-03</bid_date> </bid_tuple> into doc("bids.xml")/bids, <new_bid>{ $newbid }</new_bid> )
Expected Result:
The best bid for item 1002 had been at 1200, thus Roger's bid is at 1320.
<new_bid>1320</new_bid>
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>U04</userid> <itemno>1002</itemno> <bid>1320</bid> <bid_date>1999-03-03</bid_date> </bid_tuple> </bids>
Place a bid for Roger Smith 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. Otherwise return the current top bid.
Solution in the XQuery Update Facility:
let $uid := doc("users.xml")/users/user_tuple[name = "Roger Smith"]/userid let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno = 1007]/bid) let $newbid := $topbid * 1.1 return if($newbid <= 240) then ( insert nodes <bid_tuple> <userid>{ data($uid) }</userid> <itemno>1002</itemno> <bid>{ $newbid }</bid> <bid_date>1999-03-03</bid_date> </bid_tuple> into doc("bids.xml")/bids, <new_bid>{ $newbid }</new_bid> ) else ( <top_bid>{ $topbid }</top_bid> )
Expected Result:
Adding 10% to the best bid on item 1007 would require a bid of 247.5, which is more than the allowed limit of 240. Thus, the bids.xml document does not change.
<top_bid>225</top_bid>
Erase user Dee Linquent and the corresponding associated items and bids. Return a count of the items and bids deleted.
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, $items, $bids), <deleted> <items>{ count($items) }</items> <bids>{ count($bids) }</bids> </deleted> )
Expected Result:
<deleted> <items>2</items> <bids>2</bids> </deleted>
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>
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>
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>
This scenario demonstrates the use of an updating function that returns a non-empty XDM instance. The recursive function traverses a set of html documents by following the href attributes, returning an index structure representing the linkage hierarchy. The function also updates a list of visited documents in order to avoid a document being visited more than once.
Note:
This use case requires side-effects in the language and so is unlikely to be supported. It may be removed in a future draft of this document.
Documentation.html: The top level Wiki page.
<html> <head><title>Documentation</title></head> <body> <h1>Contents</h1> <ul> <li><a href="section1.html">Section 1</a></li> <li><a href="section2.html">Section 2</a></li> </ul> </body> </html>
section1.html:
<html> <head><title>Section 1</title></head> <body> <h1>First</h1> <p>Some interesting detail. More in the <a href="section1a.html">next section</a></p> <p>Back to the <a href="Documentation.html">index page</a></p> </body> </html>
section1a.html:
<html> <head><title>Section 1a</title></head> <body> <h1>Subsection</h1> <p>More of the same</p> <p>Back to the <a href="Documentation.html">index page</a></p> </body> </html>
section2.html:
<html> <head><title>Section 2</title></head> <body> <h1>Second</h1> <p>Summary of <a href="section1.html">section 1</a> and <a href="section1a.html">section 1a</a></p> <p>Back to the <a href="Documentation.html">index page</a></p> </body> </html>
Return the document hierarchy omitting duplicates.
Solution in the XQuery Update Facility:
declare variable $prefix := "/html/"; declare variable $visited := <visited/>; declare function local:filetree($s as xs:string, $depth) { if ($depth < 5) then <level depth="{$depth}"> <file>{ $s }</file> { let $relname := concat($prefix, $s) let $doc := doc($relname) for $href in $doc//@href where contains($href,"htm") and not(contains($href,"http")) and (every $url in $visited/url satisfies $url != $href) return ( insert node <url>{ $href }</url> into $visited, <newcall>{ local:filetree($href, $depth+1) }</newcall> ) } </level> else () }; local:filetree("Documentation.html", 1)
Expected result:
<level depth="1"> <file> Documentation.html </file> <newcall> <level depth="2"> <file> section1.html </file> <newcall> <level depth="3"> <file> section1a.html </file> </level> </newcall> </level> </newcall> <newcall> <level depth="2"> <file> section2.html </file> </level> </newcall> </level>
Create multiple files for an EPUB ebook from a single query, including JavaScript, XML manifest, XHTML book chapters and contents, CSS.
This use case illustrates creating multiple output documents in differing formats, here for an EPUB 3 ebook but the same issues apply for creating a Web app or a rich Web page with styles and scripts.
The solution presupposes functions that will create the documents that we need to write out.
Solution in the XQuery Update Facility:
let $chapters := makebook(), $js := makejs($chapters), $css := makecss($chapters), $toc := maketoc($chapters), $manifest := makemanifest($chapters, $js, $css, $toc), $output := function($method as xs:string) { <output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization"> <output:method value="{$method}"/> </output:serialization-parameters> } return ( for $c in $chapters return put($c, urifor($c), $output("xml")), put($js, "tmp/lib/js.js", $output("text")), put($css, "tmp/lib/styles.css", $output("text")), put($toc, "tmp/tox.xhtml", $output("xhtml")), put($manifest, "tmp/manifest.xhtml", $output("xhtml")) )
Expected result:
On systems that can write to files, a folder called "tmp" will be made containing XHTML, XML, JavaScript and CSS files.