W3C

XQuery Scripting Extension 3.0 Requirements and Use Cases

W3C Working Draft 16 June 2011

This version:
http://www.w3.org/TR/2010/WD-xquery-sx-30-requirements-20100916
Latest version:
http://www.w3.org/TR/xquery-sx-30-requirements
Editors:
Daniel Engovatov, W3C invited expert
Daniela Florescu, Oracle Corporation <dana.florescu@oracle.com>
Giorgio Ghelli, Pisa University <ghelli@di.unipi.it>
John Snelson, MarkLogic <john.snelson@marklogic.com>

Abstract

This document specifies requirements and use cases for the XQuery Scripting Extension.

Status of this Document

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

This is a First Public Working Draft as described in the Process Document. It was developed by the W3C XML Query Working Group, which is part of the XML Activity. The Working Group expects to eventually publish this document as a Working Group Note.

This document provides requirements and use cases for the XQuery Scripting Extension 3.0. The requirements help identify what extensions will be needed to make XQuery functional as a scripting language. The use cases are designed to help verify that the extensions defined in XQuery Scripting Extension 3.0 satisfy these requirements. Organizations and individuals should review this document to ensure that the requirements are sufficient and that the use cases cover the requirements.

Please report errors in this document using W3C's public Bugzilla system (instructions can be found at http://www.w3.org/XML/2005/04/qt-bugzilla). If access to that system is not feasible, you may send your comments to the W3C XSLT/XPath/XQuery public comments mailing list, public-qt-comments@w3.org. It will be very helpful if you include the string “[SX30Req]” 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 http://lists.w3.org/Archives/Public/public-qt-comments/.

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

Table of Contents

1 Requirements
    1.1 Goals
    1.2 Usage Scenarios
    1.3 Terminology
    1.4 General Requirements
    1.5 Relationship to XQuery 3.0
    1.6 Functionalities
2 Use Cases
    2.1 Use Case "R" - Scripting Relational Data
        2.1.1 Document Type Definition (DTD)
            2.1.1.1 DTD for users.xml
            2.1.1.2 DTD for items.xml
            2.1.1.3 DTD for bids.xml
        2.1.2 Input Data
        2.1.3 Queries and Results
            2.1.3.1 Q1
            2.1.3.2 Q2
            2.1.3.3 Q3
            2.1.3.4 Q4
    2.2 Use Case "XHTML" - AJAX Scripting with XHTML
        2.2.1 Input Data
        2.2.2 Queries and Results
            2.2.2.1 Q1
            2.2.2.2 Q2
    2.3 Use Case "WS" - XQuery for Web Services
        2.3.1 Input Data
        2.3.2 Queries and Results
            2.3.2.1 Q1
            2.3.2.2 Q2

Appendix

A References


1 Requirements

1.1 Goals

This document describes the requirements for the XQuery Scripting Extensions. XQuery 3.0 [XQuery 3.0] is a functional language that is Turing-complete and well suited to write code that ranges from simple queries to complete applications. However, some categories of applications are more easily implemented by combining XQuery 3.0 capabilities with some imperative features, such as the ability to explicitly manage internal states. The same issue stands for XQuery 3.0 enriched with the [XQuery Update Facility 3.0]. The scripting extension is intended to overcome this problem, and allow programmers to write such applications without relying on embedding XQuery 3.0 into an external language.

1.2 Usage Scenarios

The following usage scenarios describe ways in which the XQuery Scripting Extension 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 Scripting Extension, 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.

While XQuery 3.0 is very well suited to perform the main tasks of XML exploration and transformation that are common to most of these cases, some limited extensions would make it easier to use XQuery 3.0 to write some complex applications that belong to the following usage scenarios.

1.2.1 Applications that perform complex manipulations on persistent XML data

Writing applications that modify persistent data, stored in files or in databases. Such applications may need to operate on data in stages, and may need to verify that the modified data meet some constraints.

1.2.2 Complex XML to XML transformations

Writing code that performs complex XML to XML transformations.

1.2.3 Implementation of web services

Writing code that implements a web service, with the ability to access and modify persistent XML data.

1.2.4 Processing RSS feeds

Writing code that generates or aggregates RSS feeds.

1.2.5 Web service message composition and orchestration

Writing code that orchestrates web services.

1.2.6 XML application integration

Writing scripting code that calls both updating expressions and external functions, which may manipulate state and cause side-effects.

1.2.7 XML data cleaning or normalization

Writing code that performs data cleaning operations.

1.2.8 XML data integration

Writing code that accesses multiple data sources with the ability of reflecting updates from the integrated data to the data sources.

1.2.9 XML data verification

Expressing complex constraints on XML data.

1.3 Terminology

In this specification the words must, must not, should, should not, may and recommended, when are to be interpreted as described in [RFC 2119]. When these words are used in this technical sense, they occur as a hyperlink to [RFC 2119]. These words will also be used with their conventional English meaning, in which case there is no hyperlink.

Side-effects

We say that an expression has side-effects if its evaluation may affect the external environment or may affect the result of the subsequent evaluation of another expression.

1.4 General Requirements

1.4.1 Compatibility with other extensions

The XQuery Scripting Extension must not preclude the use of the other XQuery extensions developed by the Working Group.

1.4.2 Protocol Independence

The XQuery Scripting Extension must be defined independently of any protocols with which it is used.

1.4.3 Language Syntax

The XQuery Scripting Extension must have more than one syntax binding. One syntax must be convenient for humans to read and write. One syntax must be expressed in XML in a way that reflects the underlying structure of the operations.

1.4.4 Static Type Checking

The XQuery Scripting Extension should provide an optional static type checking feature.

1.4.5 Ease of programming

The XQuery Scripting Extension may include syntactic constructs to facilitate common programming tasks.

1.5 Relationship to XQuery 3.0

1.5.1 Based on Data Model

The XQuery Scripting Extension must be defined on the [XQuery and XPath Data Model 3.0].

1.5.2 Based on XQuery 3.0

The XQuery Scripting Extension must be based on XQuery 3.0. The Scripting Extension may constrain the evaluation order more than XQuery 3.0 evaluation model, but the evaluation of an expression that belongs to the syntax of XQuery 3.0 must result in a value, or in an error, that is one of those allowed by XQuery 3.0 semantics.

1.5.3 Based on the XQuery Update Facility

The XQuery Scripting Extension should be based on the [XQuery Update Facility 3.0]. If it is based on the XQuery Update Facility, it may constrain the evaluation order in ways that are not required by the XQuery Update Facility evaluation model. However, if both the XQuery Update Facility and the XQuery Scripting Extension specify a result value for a given expression, they must specify the same result value.

1.5.4 Optimization

The XQuery Scripting Extension should be designed in such a way that the ability of a processor to optimize queries or parts of a query that make no use of the extension is not compromised.

1.6 Functionalities

1.6.1 Controlling the order of evaluation of functions and expressions that have side-effects

It must be possible for the programmer to control the evaluation order of expressions and function calls that perform side-effects.

1.6.2 Preserving state during computation

It must be possible to write code where pieces of data are bound to variables which are passed to further stages of the computation, and it must be possible to modify the value associated to such variables.

1.6.3 Returning values from expressions that have side-effects

It must be possible to write code that has side-effects and returns a value.

1.6.4 Ability to see the results of side-effects during computation

It must be possible for an expression to observe some side-effects caused by other expressions.

1.6.5 Controlling the scope of snapshot, isolation, atomicity

The [XQuery Update Facility 3.0] defines a snapshot as the scope within which expressions are evaluated with respect to a fixed XDM instance and updates are held pending. The extension may provide the ability to control snapshots. The extension may provide the ability to identify pieces of code whose execution should be isolated from the outer environment. It may be possible to indicate that some pieces of code must be executed atomically, with respect to failures.

Editorial note 2012-01-27
The XML Query Working Group intends to explore whether or not the Scripting Extension should define a mechanism to control transaction boundaries.

2 Use Cases

The use cases listed below were created by the XML Query Working Group to illustrate important applications for an XQuery scripting extension.

2.1 Use Case "R" - Scripting Relational Data

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 )

2.1.1 Document Type Definition (DTD)

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

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

                      

2.1.2 Input Data

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 ... 
</items>
<users>
  <user_tuple>
    <userid>U01</userid>
    <name>Tom Jones</name>
    <rating>B</rating>
  </user_tuple>
    ... Snip ... 
</users>
<bids>
  <bid_tuple> 
    <userid>U02</userid> 
    <itemno>1001</itemno> 
    <bid>35</bid> 
    <bid_date>1999-01-07</bid_date> 
    </bid_tuple> 
  <bid_tuple> 
    ... Snip ... 
</bids>
                    

The entire data set is represented by the following table:

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

2.1.3 Queries and Results

2.1.3.1 Q1

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 Scripting Extension:

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>
                                                
2.1.3.2 Q2

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 Scripting Extension:

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>
            
2.1.3.3 Q3

Erase user Dee Linquent and the corresponding associated items and bids. Return a count of the items and bids deleted.

Solution in the XQuery Scripting Extension:

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>

2.1.3.4 Q4

Monitor the bidding on the helicopter. If Roger Smith does not have the current highest bid, add a bid for him that is one higher than the top bid, unless the bid amount exceeds a given limit. Stop monitoring when the auction has finished.

Solution in the XQuery Scripting Extension:

Editorial note 2008-01-25
A naive execution of this query would form a busy loop waiting for the auction to end. This is not very desirable, so it's possible an alternative solution should be found.
declare variable $uid := doc("users.xml")/users/user_tuple
  [name = "Roger Smith"]/userid;
declare variable $item := doc("items.xml")/items/item_tuple
  [description = "Helicopter"];
declare assignable variable $result :=
  "Error: The auction has already ended or no bids were placed";
declare assignable variable $maximumExceeded := false();

while(xs:date($item/end_date) >= fn:current-date() and not($maximumExceeded)) {
  let $bids := doc("bids.xml")/bids/bid_tuple[itemno = $item/itemno]
  let $topbid := max($bids/bid)
  let $newbid := $topbid + 1
  where $bids[bid = $topbid]/userid != $uid
  return
    if($newbid <= 60000) then (
      insert nodes
        <bid_tuple>
          { $uid, $item/itemno }
          <bid>{ $newbid }</bid> 
          <bid_date>{ fn:current-date() }</bid_date> 
        </bid_tuple>
      into doc("bids.xml")/bids;
      $result := concat("What a bargain! You got a helicopter for ",
        $newbid);
    ) else (
      $result := "Bidding exceeded 60000";
      $maximumExceeded := true();
    )
};

$result;

Expected Result:

Since this document was published after the end date for the auction ("1999-05-25"), the while loop will never be executed.

Error: The auction has already ended or no bids were placed

2.2 Use Case "XHTML" - AJAX Scripting with XHTML

XQuery is ideally suited to manipulating the XML trees of XHTML. This use case speculates that XQuery could be used in the way Javascript is now, to modify an XHTML web page whilst it is being displayed. In this way XQuery can be used to implement effects like those commonly referred to by the acronym AJAX.

This use case deals with a web page that can be used to perform a search in a book database. In all queries, there is an assumption that the xhtml document is supplied as the context item.

2.2.1 Input Data

The starting state of the web page consists of only a simple XHTML form.

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Book Search</title>
  </head>
  <body>
    <form>
      Book Name: <input type="text" id="txtBookName"/>
      <input type="button" id="btnSend" value="Start Search"/>
    </form>
  </body>
</html>

2.2.2 Queries and Results

2.2.2.1 Q1

Write a script to act as an "onclick" event handler for the "btnSend" form button. The script calls a web service to search for the book entered by the user and retrieve detailed information for the book. While the user is waiting for the web service the message "Loading Book" is displayed. This message is later replaced with the detailed information for the book.

Input web page:

The web browser has already updated the content of the form's text input with the user's search string, "XQuery".

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Book Search</title>
  </head>
  <body>
    <form>
      Book Name: <input type="text" id="txtBookName">XQuery</input>
      <input type="button" id="btnSend" value="Start Search"/>
    </form>
  </body>
</html>

Solution in the XQuery Scripting Extension:

The element that caused the event is supplied as an external variable called $eventNode. The web service is called using the external functions "book:search", and "book:get".

declare namespace xhtml="http://www.w3.org/1999/xhtml";
declare namespace book="http://www.example.com/booksearch";

declare simple function book:search($name as xs:string) as element(book)* external;
declare simple function book:get($isbn as xs:string) as element(bookinfo) external;

declare variable $eventNode as element() external;
declare assignable variable $searchResults := ();

insert node <xhtml:div>Loading Book</xhtml:div>
after /xhtml:html/xhtml:body/xhtml:form;

$searchResults :=
  book:search($eventNode/preceding-sibling::xhtml:input[1]);

if($searchResults) then (
  replace node /xhtml:html/xhtml:body/xhtml:div
  with <xhtml:div>{
    book:get($searchResults[1]/isbn)/html/node()
  }</xhtml:div>;
)
else (
  replace node /xhtml:html/xhtml:body/xhtml:div
  with <xhtml:div>No books found!</xhtml:div>;
);

Results returned to the query from the function call book:search("XQuery"):

<book>
  <title>XQuery from the Experts: A Guide to the W3C XML Query Language</title>
  <isbn>0321180607</isbn>
</book>
<book>
  <title>XQuery: The XML Query Language</title>
  <isbn>0321165810</isbn>
</book>

Results returned to the query from the function call book:get("0321180607"):

<bookinfo>
  <title>XQuery from the Experts: A Guide to the W3C XML Query Language</title>
  <isbn>0321180607</isbn>
  <html>
    <h2 xmlns="http://www.w3.org/1999/xhtml">XQuery from the Experts: A Guide to the W3C XML Query Language</h2>
    ISBN: 0321180607
  </html>
</bookinfo>

Expected intermediate content of the web page:

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Book Search</title>
  </head>
  <body>
    <form>
      Book Name: <input type="text" id="txtBookName">XQuery</input>
      <input type="button" id="btnSend" value="Start Search"/>
    </form>
    <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">Loading book</xhtml:div>
  </body>
</html>

Expected resulting content of the web page:

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Book Search</title>
  </head>
  <body>
    <form>
      Book Name: <input type="text" id="txtBookName">XQuery</input>
      <input type="button" id="btnSend" value="Start Search"/>
    </form>
    <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">
      <h2>XQuery from the Experts: A Guide to the W3C XML Query Language</h2>
      ISBN: 0321180607
    </xhtml:div>
  </body>
</html>
2.2.2.2 Q2

Write a script to act as an "onclick" event handler for the "btnSend" form button. The script calls a web service to search for the book entered by the user, and uses an additional web service to find which libraries have these books on the shelves. The information received is displayed asynchronously as it arrives.

Input web page:

The web browser has already updated the content of the form's text input with the user's search string, "XQuery".

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Book Search</title>
  </head>
  <body>
    <form>
      Book Name: <input type="text" id="txtBookName">XQuery</input>
      <input type="button" id="btnSend" value="Start Search"/>
    </form>
  </body>
</html>

Solution in the XQuery Scripting Extension:

The element that caused the event is supplied as an external variable called $eventNode. The web services are called using the external functions "book:search", and "library:find".

declare namespace xhtml="http://www.w3.org/1999/xhtml";
declare namespace book="http://www.example.com/booksearch";
declare namespace library="http://www.example.com/library";

declare simple function book:search($name as xs:string)
  as element(book)* external;
declare simple function library:find($isbn as xs:string)
  as element(library)* external;

declare variable $eventNode as element() external;
declare assignable variable $table := ();

insert node <xhtml:div><xhtml:table/></xhtml:div>
after /xhtml:html/xhtml:body/xhtml:form;
$table := //xhtml:table;

for $book in book:search($eventNode/preceding-sibling::xhtml:input[1])
return (
  insert node
    <xhtml:tr>
      <xhtml:td>{data($book/title)}</xhtml:td>
      <xhtml:td>{data($book/isbn)}</xhtml:td>
      <xhtml:td/>
    </xhtml:tr>
  as last into $table;
);

for $row in $table/xhtml:tr
return (
  replace value of node $row/xhtml:td[3]
  with string-join(library:find($row/xhtml:td[2])/name, ", ");
);

Results returned to the query from the function call book:search("XQuery"):

<book>
  <title>XQuery from the Experts: A Guide to the W3C XML Query Language</title>
  <isbn>0321180607</isbn>
</book>
<book>
  <title>XQuery: The XML Query Language</title>
  <isbn>0321165810</isbn>
</book>

Results returned to the query from the function call library:find("0321180607"):

<library>
  <name>Bodleian Library</name>
  <url>http://www.bodley.ox.ac.uk/</url>
  <lending>no</lending>
</library>
<library>
  <name>Radcliffe Science Library</name>
  <url>http://www.ouls.ox.ac.uk/rsl/</url>
  <lending>yes</lending>
</library>

Results returned to the query from the function call library:find("0321165810"):

<library>
  <name>Radcliffe Science Library</name>
  <url>http://www.ouls.ox.ac.uk/rsl/</url>
  <lending>yes</lending>
</library>

Expected resulting content of the web page:

The web page will be altered as the results are received from the web services, but the final result will look like this.

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Book Search</title>
  </head>
  <body>
    <form>
      Book Name: <input type="text" id="txtBookName">XQuery</input>
      <input type="button" id="btnSend" value="Start Search"/>
    </form>
    <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">
      <xhtml:table>
        <xhtml:tr>
          <xhtml:td>XQuery from the Experts: A Guide to the W3C XML Query Language</xhtml:td>
          <xhtml:td>0321180607</xhtml:td>
          <xhtml:td>Bodleian Library, Radcliffe Science Library</xhtml:td>
        </xhtml:tr>
        <xhtml:tr>
          <xhtml:td>XQuery: The XML Query Language</xhtml:td>
          <xhtml:td>0321165810</xhtml:td>
          <xhtml:td>Radcliffe Science Library</xhtml:td>
        </xhtml:tr>
      </xhtml:table>
    </xhtml:div>
  </body>
</html>

2.3 Use Case "WS" - XQuery for Web Services

This use case deals with the implementation of a REST based web service, specifically a micro-blog.

2.3.1 Input Data

The default collection contains a forest of micro blog documents, one for each user. Initially the forest contains these documents.

John's micro-blog:

<micro-blog user="john">
  <entry timestamp="2007-10-17T10:02:53+01:00">
    <text>Still reading email...</text>
  </entry>
  <entry timestamp="2007-10-17T20:19:31+01:00">
    <text>Writing XQuery Scripting Extension use cases (ideas, anyone?)</text>
  </entry>
  <entry timestamp="2007-10-18T00:43:02+01:00">
    <text>Thinking of going to bed</text>
  </entry>
</micro-blog>

Emily's micro-blog:

<micro-blog user="emily">
  <entry timestamp="2007-10-16T18:12:51+01:00">
    <text>So how do you use a micro-blog?</text>
  </entry>
  <entry timestamp="2007-10-16T18:13:20+01:00">
    <text>Ah, I see</text>
  </entry>
  <entry timestamp="2007-10-17T07:33:44+01:00">
    <text>Morning, everybody!</text>
  </entry>
</micro-blog>

A document containing the blog access log:

<log>
</log>

2.3.2 Queries and Results

2.3.2.1 Q1

Process a request from John to add a blog entry, returning a confirmation XHTML page.

The element representing the request:

<request>
  <method>POST</method>
  <url>http://blog.example.com/john/add</url>
  <param name="text">Making a post to my XQuery blog engine</param>
</request>

Solution in the XQuery Scripting Extension:

The request element is bound to the external variable $request.

declare variable $request as element(request) external;

declare simple function local:error($message)
{
  <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <title>Error</title>
    </head>
    <body>
      <h1>Error</h1>
      <p>{ $message }</p>
    </body>
  </html>
};

if($request/method = "POST") then () else
  exit returning local:error(concat("You cannot use the ",
    $request/method, " method with this URL."));

let $user := replace($request/url, "^http://.*/([^/]+)/add$", "$1")
let $blog := collection()/micro-blog[@user = $user]
return (
  if($blog) then () else
    exit returning local:error("Unknown user");

  insert node
    <entry timestamp="{ current-dateTime() }">
      <text>{ data($request/param[@name = "text"]) }</text>
    </entry>
  as last into $blog;

  <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <title>Blog entry added for { $user }</title>
    </head>
    <body>
      <h1>Blog entry added for { $user }</h1>
      <p>{ data($request/param[@name = "text"]) }</p>
    </body>
  </html>;
);

Expected Result:

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Blog entry added for john</title>
  </head>
  <body>
    <h1>Blog entry added for john</h1>
    <p>Making a post to my XQuery blog engine</p>
  </body>
</html>

Expected resulting content of John's micro-blog:

<micro-blog user="john">
  <entry timestamp="2007-10-17T10:02:53+01:00">
    <text>Still reading email...</text>
  </entry>
  <entry timestamp="2007-10-17T20:19:31+01:00">
    <text>Writing XQuery Scripting Extension use cases (ideas, anyone?)</text>
  </entry>
  <entry timestamp="2007-10-18T00:43:02+01:00">
    <text>Thinking of going to bed</text>
  </entry>
  <entry timestamp="2007-10-18T08:53:9+01:00">
    <text>Making a post to my XQuery blog engine</text>
  </entry>
</micro-blog>
2.3.2.2 Q2

Process the same request from John, using a function to check that "john" is a valid user name and to log the event.

The element representing the request:

<request>
  <method>POST</method>
  <url>http://blog.example.com/john/add</url>
  <param name="text">Making a post to my XQuery blog engine</param>
</request>

Solution in the XQuery Scripting Extension:

The request element is bound to the external variable $request.

declare variable $request as element(request) external;

declare sequential function local:check-user-and-log($username as xs:string) 
  as element(micro-blog)?
{
  declare $entry as element() :=
    <access-attempt>
      <timestamp>{fn:current-dateTime()}</timestamp>
      <user-name>{$username}</user-name>
      <access-allowed/>
    </access-attempt>;
  declare $blog as element(micro-blog)? :=
    collection()/micro-blog[@user = $username];

  if($blog) then
    replace value of node $entry/access-allowed with "Yes"
  else
    replace value of node $entry/access-allowed with "No";

  insert node $entry as last into collection()/log;

  $blog;
}; 


declare simple function local:error($message)
{
  <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <title>Error</title>
    </head>
    <body>
      <h1>Error</h1>
      <p>{ $message }</p>
    </body>
  </html>
};

if($request/method = "POST") then () else
  exit returning local:error(concat("You cannot use the ",
    $request/method, " method with this URL."));

let $user := replace($request/url, "^http://.*/([^/]+)/add$", "$1")
let $blog := local:check-user-and-log($user)
return (
  if($blog) then () else
    exit returning local:error("Unknown user");

  insert node
    <entry timestamp="{ current-dateTime() }">
      <text>{ data($request/param[@name = "text"]) }</text>
    </entry>
  as last into $blog;

  <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <title>Blog entry added for { $user }</title>
    </head>
    <body>
      <h1>Blog entry added for { $user }</h1>
      <p>{ data($request/param[@name = "text"]) }</p>
    </body>
  </html>;
);

Expected Result:

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Blog entry added for john</title>
  </head>
  <body>
    <h1>Blog entry added for john</h1>
    <p>Making a post to my XQuery blog engine</p>
  </body>
</html>

Expected resulting content of John's micro-blog:

<micro-blog user="john">
  <entry timestamp="2007-10-17T10:02:53+01:00">
    <text>Still reading email...</text>
  </entry>
  <entry timestamp="2007-10-17T20:19:31+01:00">
    <text>Writing XQuery Scripting Extension use cases (ideas, anyone?)</text>
  </entry>
  <entry timestamp="2007-10-18T00:43:02+01:00">
    <text>Thinking of going to bed</text>
  </entry>
  <entry timestamp="2007-10-18T08:53:9+01:00">
    <text>Making a post to my XQuery blog engine</text>
  </entry>
</micro-blog>

Expected resulting content of the log:

<log>
  <access-attempt>
    <timestamp>2007-10-18T08:53:9+01:00</timestamp>
    <user-name>john</user-name>
    <access-allowed>Yes</access-allowed>
  </access-attempt>
</log>

A References

RFC 2119
S. Bradner. Key Words for use in RFCs to Indicate Requirement Levels. IETF RFC 2119. See http://www.ietf.org/rfc/rfc2119.txt.
XQuery and XPath Data Model 3.0
World Wide Web Consortium. XQuery and XPath Data Model 3.0. W3C Working Draft, 16 September 2010. See http://www.w3.org/TR/xpath-datamodel-30/.
XQuery 3.0
World Wide Web Consortium. XQuery 3.0. W3C Working Draft, 16 September 2010. See http://www.w3.org/TR/xquery-30/.
XQuery Update Facility 3.0
World Wide Web Consortium. XQuery Update Facility 3.0 . W3C Working Draft, 16 September 2010. See http://www.w3.org/TR/xquery-update-30/.
XML Query Use Cases
World Wide Web Consortium. XML Query Use Cases. W3C Working Group Note, 23 March 2007. See http://www.w3.org/TR/xquery-use-cases/.