W3C

XQuery 3.0 Use Cases

W3C Working Group Note 08 April 2014

This version:
http://www.w3.org/TR/2014/NOTE-xquery-30-use-cases-20140408/
Latest version:
http://www.w3.org/TR/xquery-30-use-cases/
Previous versions:
http://www.w3.org/TR/2013/WD-xquery-30-use-cases-20130108/, http://www.w3.org/TR/2012/WD-xquery-30-use-cases-20120327/, http://www.w3.org/TR/2010/WD-xquery-30-use-cases-20101214/, http://www.w3.org/TR/2008/WD-xquery-11-use-cases-20081203/, http://www.w3.org/TR/2008/WD-xquery-11-use-cases-20080711/
Editors:
Jonathan Robie, EMC Corporation <[email protected]>
Tim Kraska, FLWOR Foundation <[email protected]>

This document is also available in these non-normative formats: XML.


Abstract

This document specifies usage scenarios for XML Query (XQuery) 3.0.

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 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 provides a number of use cases designed to evaluate XQuery 3.0, the requirements for which are specified in [XQuery 3.0 Requirements].

This document incorporates changes made against the previous publication of the Working Draft. Changes to this document since the previous publication of the Working Draft are detailed in B Change Log.

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, [email protected]. It will be very helpful if you include the string “[XQuery30UC]” 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 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.

Table of Contents

1 Use Cases for XML Query 3.0
2 Shopping Scenario: Schema and Data
    2.1 Schema
    2.2 Sample Data
3 Use Case "Group By" - Queries which require value-based grouping
    3.1 Schema and Sample Data
        3.1.1 Schema Q7-Q8
        3.1.2 Sample Data Q7-Q8
    3.2 Queries and Results
        3.2.1 Q1
        3.2.2 Q2
        3.2.3 Q3
        3.2.4 Q4
        3.2.5 Q5
        3.2.6 Q6
        3.2.7 Q7
        3.2.8 Q8
4 Use Case "Windowing" - Queries which require windowing
    4.1 Schema and Sample Data
        4.1.1 XML Schema for Q1
        4.1.2 Sample Data for Q1
        4.1.3 XML Schema for Q2
        4.1.4 Sample Data for Q2
        4.1.5 XML Schema for Q3
        4.1.6 Sample Data for Q3
        4.1.7 XML Schema for Q4-Q6
        4.1.8 Sample Data for Q4-Q6
        4.1.9 XML Schema for Q7-Q13
        4.1.10 Sample Data for Q7-Q13
        4.1.11 XML Schema for Q14-Q16
        4.1.12 Sample Data for Q14-Q16
        4.1.13 XML Schema for Q17-Q19
        4.1.14 Sample Data for Q17-Q19
    4.2 Queries and Results
        4.2.1 Q1
        4.2.2 Q2
        4.2.3 Q3
        4.2.4 Q4
        4.2.5 Q5
        4.2.6 Q6
        4.2.7 Q7
        4.2.8 Q8
        4.2.9 Q9
        4.2.10 Q10
        4.2.11 Q11
        4.2.12 Q12
        4.2.13 Q13
        4.2.14 Q14
        4.2.15 Q15
        4.2.16 Q16
        4.2.17 Q17
        4.2.18 Q18
        4.2.19 Q19
5 Use Case "Count" - Queries which require output numbering
    5.1 Schema and Sample Data
    5.2 Queries and Results
        5.2.1 Q1
        5.2.2 Q2
        5.2.3 Q3
6 Use Case "Outer For" - Queries which require outer joins
    6.1 Schema and Sample Data
    6.2 Queries and Results
        6.2.1 Q1
        6.2.2 Q2
7 Use Case "Try-Catch" - Queries which require to recover from errors
    7.1 Sample Data
    7.2 Queries and Results
        7.2.1 Q1
        7.2.2 Q2
        7.2.3 Q3

Appendices

A Acknowledgements (Non-Normative)
B Change Log (Non-Normative)
    B.1 30 Mar 2011
    B.2 30 January 2008
    B.3 17 November 2008
C References (Non-Normative)


1 Use Cases for XML Query 3.0

The use cases listed below were created by the XML Query Working Group to illustrate important applications for the new features in XQuery 3.0. Each use case is focused on a specific application area, and contains a XML Schema and example input data. Each use case specifies a set of queries that might be applied to the input data, and the expected results for each query. Since the English description of each query is concise, the expected results form an important part of the definition of each query, specifying the expected output format.

Most of the listed use cases are based on a simple shopping scenario described in section Schema and Data. Use cases which require special data have a seperate subsection describing the XML Schema and input data. All use cases assume that input is provided in the form of one or more documents with specific names. For instance, the products in a document may be accessed with expressions like this:

doc("products.xml")//product

Several implementors have asked us to make the queries from these use cases available in a separate file in order to make it easier for them to test their parsers. These queries may be found in [Use Case Sample Queries]

To make output more readable, the output of queries has been formatted using whitespace which may not be returned by a query processor. This whitespace should not be considered normative for the correctness of results.

These queries were tested with a dynamic implementation of XQuery. Some queries may require additional type declarations to be used with an implementation that implements the Static Typing feature.

2 Shopping Scenario: Schema and Data

If not stated otherwise all use cases in this document are based on a simplified shopping scenario containing three documents. The first document, products.xml, contains a list of products, whereas stores.xml includes a list of stores, and sales-records.xml contains the list of sales.

2.1 Schema

The document product.xml uses the following XML Schema:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="products">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="product" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="name" type="xs:string"/>
                            <xs:element name="category" type="xs:string"/>
                            <xs:element name="price" type="xs:double"/>
                            <xs:element name="cost" type="xs:double"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

The sales-records.xml document follows this XML Schema:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="sales">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="record" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="product-name" type="xs:string"/>
                            <xs:element name="store-number" type="xs:integer"/>
                            <xs:element name="qty" type="xs:integer"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

The stores.xml document is valid to this XML Schema:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="stores">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="store" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="store-number" type="xs:byte"/>
                            <xs:element name="state" type="xs:string"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

2.2 Sample Data

The content of the document products.xml is:

<products>
  <product>
    <name>broiler</name>
    <category>kitchen</category>
    <price>100</price>
    <cost>70</cost>
  </product>
  <product>
    <name>toaster</name>
    <category>kitchen</category>
    <price>30</price>
    <cost>10</cost>
  </product>
  <product>
    <name>blender</name>
    <category>kitchen</category>
    <price>50</price>
    <cost>25</cost>
  </product>
  <product>
    <name>socks</name>
    <category>clothes</category>
    <price>5</price>
    <cost>2</cost>
  </product>
  <product>
    <name>shirt</name>
    <category>clothes</category>
    <price>10</price>
    <cost>3</cost>
  </product>
</products>

The content of sales-records.xml is:

<sales>
  <record>
    <product-name>broiler</product-name>
    <store-number>1</store-number>
    <qty>20</qty>
  </record>
  <record>
    <product-name>toaster</product-name>
    <store-number>2</store-number>
    <qty>100</qty>
  </record>
  <record>
    <product-name>toaster</product-name>
    <store-number>2</store-number>
    <qty>50</qty>
  </record>
  <record>
    <product-name>toaster</product-name>
    <store-number>3</store-number>
    <qty>50</qty>
  </record>
  <record>
    <product-name>blender</product-name>
    <store-number>3</store-number>
    <qty>100</qty>
  </record>
  <record>
    <product-name>blender</product-name>
    <store-number>3</store-number>
    <qty>150</qty>
  </record>
  <record>
    <product-name>socks</product-name>
    <store-number>1</store-number>
    <qty>500</qty>
  </record>
  <record>
    <product-name>socks</product-name>
    <store-number>2</store-number>
    <qty>10</qty>
  </record>
  <record>
    <product-name>shirt</product-name>
    <store-number>3</store-number>
    <qty>10</qty>
  </record>
</sales>

The content of stores.xml is:

<stores>
  <store>
    <store-number>1</store-number>
    <state>CA</state>
  </store>
  <store>
    <store-number>2</store-number>
    <state>CA</state>
  </store>
  <store>
    <store-number>3</store-number>
    <state>MA</state>
  </store>
  <store>
    <store-number>4</store-number>
    <state>WA</state>
  </store>
</stores>

3 Use Case "Group By" - Queries which require value-based grouping

This use case contains several sample queries in which value based grouping is needed.

3.1 Schema and Sample Data

Queries 1-6 are based on a simplified shop scenario with products, sales records and different shop locations. The schema and data can be found in section Schema and Data. Queries 7 and 8 are based on a bibliography document shown below:

3.1.1 Schema Q7-Q8

Q7 and Q8 use an input document named "books.xml", with the following XML Schema:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="bib">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="book" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="author" type="xs:string" maxOccurs="unbounded"/>
                            <xs:element name="title" type="xs:string"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

3.1.2 Sample Data Q7-Q8

Here are the contents of books.xml:

<bib>
  <book>
    <author>Jim Melton</author>
    <author>Alan Simon</author>
    <title>SQL:1999</title>
  </book>
  <book>
    <author>Jim Melton</author>
    <title>Advanced SQL:1999</title>
  </book>
  <book>
    <author>Alan Simon</author>
    <title>Strategic Database Technology</title>
  </book>
  <book>
    <author>Jim Melton</author>
    <author>Andrew Eisenberg</author>
    <title>Understanding SQL and Java Together</title>
  </book>
  <book>
    <author>Jim Melton</author>
    <author>Stephen Buxton</author>
    <title>Querying XML</title>
  </book>
</bib>

3.2 Queries and Results

3.2.1 Q1

Group sales by product, list name and total quantity of each product.

Solution in XQuery:

<sales-qty-by-product>{
  for $sales in doc("sales-records.xml")/*/record
  let $pname := $sales/product-name
  group by $pname
  order by $pname
  return
    <product name="{$pname}">{
      sum($sales/qty)
    }</product>
}</sales-qty-by-product> 

Expected Result:

<sales-qty-by-product>
  <product name="blender">250</product>
  <product name="broiler">20</product>
  <product name="shirt">10</product>
  <product name="socks">510</product>
  <product name="toaster">200</product>
</sales-qty-by-product>

3.2.2 Q2

Group sales by state (a property of the store) and category (a property of the product). Order groups by the grouping keys. For each group, show the total quantity sold.

Solution in XQuery:

<result>{
  for $sales in doc("sales-records.xml")/*/record
  let $state := doc("stores.xml")/*/store[store-number = $sales/store-number]/state
  let $category := doc("products.xml")/*/product[name = $sales/product-name]/category
  group by $state, $category
  order by $state, $category
  return
    <group>
      <state>{$state}</state>
      <category>{$category}</category>
      <total-qty>{sum($sales/qty)}</total-qty>
    </group>
}</result>

Expected Result:

<result>
  <group>
    <state>CA</state>
    <category>clothes</category>
    <total-qty>510</total-qty>
  </group>
  <group>
    <state>CA</state>
    <category>kitchen</category>
    <total-qty>170</total-qty>
  </group>
  <group>
    <state>MA</state>
    <category>clothes</category>
    <total-qty>10</total-qty>
  </group>
  <group>
    <state>MA</state>
    <category>kitchen</category>
    <total-qty>300</total-qty>
  </group>
</result>

3.2.3 Q3

Group sales by state (a property of the store) and category (a property of the product). Order groups by the grouping keys. For each group, show the total revenue (defined as sales/qty * product/price).

Solution in XQuery:

<result>{
  for $sales in doc("sales-records.xml")/*/record
  let $state := doc("stores.xml")/*/store[store-number = $sales/store-number]/state,
    $product := doc("products.xml")/*/product[name = $sales/product-name],
    $category := $product/category,
    $revenue := $sales/qty * $product/price
  group by $state, $category
  order by $state, $category
  return
    <group>
      <state>{$state}</state>
      <category>{$category}</category>
      <total-revenue>{sum($revenue)}</total-revenue>
    </group>
}</result>

Expected Result:

<result>
  <group>
    <state>CA</state>
    <category>clothes</category>
    <total-revenue>2550</total-revenue>
  </group>
  <group>
    <state>CA</state>
    <category>kitchen</category>
    <total-revenue>6500</total-revenue>
  </group>
  <group>
    <state>MA</state>
    <category>clothes</category>
    <total-revenue>100</total-revenue>
  </group>
  <group>
    <state>MA</state>
    <category>kitchen</category>
    <total-revenue>14000</total-revenue>
  </group>
</result>

3.2.4 Q4

Combine the input documents into a three-level hierarchy based on state, category, and product. At the product level, show the total quantity sold of each product. List items alphabetically at each level of the hierarchy.

Solution in XQuery:

<result>{
  for $store in doc("stores.xml")/*/store
  let $state := $store/state
  group by $state
  order by $state
  return
    <state name="{$state}">{
      for $product in doc("products.xml")/*/product
      let $category := $product/category
      group by $category
      order by $category
      return
        <category name="{$category}">{
          for $sales in doc("sales-records.xml")/*/record[store-number = $store/store-number
            and product-name = $product/name]
          let $pname := $sales/product-name
          group by $pname
          order by $pname
          return
            <product name="{$pname}" total-qty="{sum($sales/qty)}" />
          }</category>
    }</state>
}</result>

Expected Result:

<result>
  <state name="CA">
    <category name="clothes">
      <product name="socks" total-qty="510"/>
    </category>
    <category name="kitchen">
      <product name="broiler" total-qty="20"/>
      <product name="toaster" total-qty="150"/>
    </category>
  </state>
  <state name="MA">
    <category name="clothes">
      <product name="shirt" total-qty="10"/>
    </category>
    <category name="kitchen">
      <product name="blender" total-qty="250"/>
      <product name="toaster" total-qty="50"/>
    </category>
  </state>
</result>

3.2.5 Q5

List all stores in ascending order by store number. For each store, list the products sold in that store, in descending order by quantity sold. Illustrates ordering among and within groups.

Solution in XQuery:

<result>{
  for $sales in doc("sales-records.xml")/*/record
  let $storeno := $sales/store-number
  group by $storeno
  order by $storeno
  return
    <store number = "{$storeno}">{
      for $s in $sales
      order by xs:int($s/qty) descending
      return
        <product name = "{$s/product-name}" qty = "{$s/qty}"/>
    }</store>
}</result>

Expected Result:

<result>
  <store number="1">
    <product name="socks" qty="500"/>
    <product name="broiler" qty="20"/>
  </store>
  <store number="2">
    <product name="toaster" qty="100"/>
    <product name="toaster" qty="50"/>
    <product name="socks" qty="10"/>
  </store>
  <store number="3">
    <product name="blender" qty="150"/>
    <product name="blender" qty="100"/>
    <product name="toaster" qty="50"/>
    <product name="shirt" qty="10"/>
  </store>
</result>

3.2.6 Q6

List all stores whose total profit is greater than 100, in descending order by total profit. Note: total profit for a store is the sum over all sales in that store, of the quantity sold times the difference between price and cost for the item sold. Illustrates cross-document computation, filtering of groups, ordering by a non-grouping key.

Solution in XQuery:

<result>{
  for $sales in doc("sales-records.xml")/*/record
  let $storeno := $sales/store-number,
    $product := doc("products.xml")/*/product[name = $sales/product-name],
    $prd := $product,
    $profit := $sales/qty * ($prd/price - $prd/cost)
  group by $storeno
  let $total-store-profit := sum($profit)
  where $total-store-profit > 100
  order by $total-store-profit descending
  return
    <store number = "{$storeno}" total-profit = "{$total-store-profit}"/>
 }</result>

Expected Result:

<result>
  <store number="3" total-profit="7320"/>
  <store number="2" total-profit="3030"/>
  <store number="1" total-profit="2100"/>
</result>

3.2.7 Q7

Group books by author. Create a group for each individual author. A book with multiple authors should appear in the groups for each of its authors. Alphabetize the authors and the book titles within each author group.

Solution in XQuery:

<result>{
  for $book in doc("books.xml")/*/book
  for $author in $book/author
  group by $author
  order by $author
  return
  <author name="{$author}">{
    for $b in $book
    order by $b/title
    return
      <title> {fn:data($b/title)} </title>
  }</author>
}</result>

Expected Result:

<result>
  <author name="Alan Simon">
    <title>SQL:1999</title>
    <title>Strategic Database Technology</title>
  </author>
  <author name="Andrew Eisenberg">
    <title>Understanding SQL and Java Together</title>
  </author>
  <author name="Jim Melton">
    <title>Advanced SQL:1999</title>
    <title>Querying XML</title>
    <title>SQL:1999</title>
    <title>Understanding SQL and Java Together</title>
  </author>
  <author name="Stephen Buxton">
    <title>Querying XML</title>
  </author>
</result>

3.2.8 Q8

Group books by author. Create a group for each distinct ordered list of authors. Each book should be grouped with other books that have the same ordered list of authors. Alphabetize the book titles within each group.

Solution in XQuery:

<result>{
  for $book in doc("books.xml")/*/book
  let $author-list := fn:string-join($book/author, ', ')
  group by $author-list
  order by $author-list
  return
    <author-list names="{$author-list}">{
      for $b in $book
      order by $b/title
      return
        <title> {fn:data($b/title)} </title>
    }</author-list>
}</result>

Expected Result:

<result>
  <author-list names="Alan Simon">
    <title>Strategic Database Technology</title>
  </author-list>
  <author-list names="Jim Melton">
    <title>Advanced SQL:1999</title>
  </author-list>
  <author-list names="Jim Melton, Alan Simon">
    <title>SQL:1999</title>
  </author-list>
  <author-list names="Jim Melton, Andrew Eisenberg">
    <title>Understanding SQL and Java Together</title>
  </author-list>
  <author-list names="Jim Melton, Stephen Buxton">
    <title>Querying XML</title>
  </author-list>
</result>

4 Use Case "Windowing" - Queries which require windowing

This use case covers queries that require windowing or positional grouping, which can be seen as a special form of windowing. Windowing means that the queries require selecting subsequences based on certain characterisics of an underlying sequence.

4.1 Schema and Sample Data

Windowing is required in various scenarios from formatting up to streaming applications. The listed queries try to cover different scenarios and require therefore also various types of input data. The following sections describe for every query the used data and the according schema.

4.1.1 XML Schema for Q1

Q1 uses an input document named arrange_rows.xml, with the following XML Schema arrange_rows.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="doc">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="data" type="xs:string" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

4.1.2 Sample Data for Q1

The content of arrange_rows.xml is:

<doc>
  <data>Green</data>
  <data>Pink</data>
  <data>Lilac</data>
  <data>Turquoise</data>
  <data>Peach</data>
  <data>Opal</data>
  <data>Champagne</data>
</doc>

4.1.3 XML Schema for Q2

Q2 uses an input document named head_para.xml, with the following XML Schema named head_para.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="body">
        <xs:complexType>
            <xs:sequence>
                <xs:sequence maxOccurs="unbounded">
                    <xs:element name="h2" type="xs:string"/>
                    <xs:element name="p" type="xs:string" maxOccurs="unbounded"/>
                </xs:sequence>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

4.1.4 Sample Data for Q2

The content of head_para.xml is:

<body>
  <h2>heading1</h2>
  <p>para1</p>
  <p>para2</p>
  <h2>heading2</h2>
  <p>para3</p>
  <p>para4</p>
  <p>para5</p>
</body>

4.1.5 XML Schema for Q3

Q3 uses an input document named term_def_list.xml, with the following XML Schema named term_def_list.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="doc">
        <xs:complexType>
            <xs:sequence>
                <xs:sequence maxOccurs="unbounded">
                    <xs:element name="dt" type="xs:string" maxOccurs="unbounded"/>
                    <xs:element name="dd" type="xs:string" maxOccurs="unbounded"/>
                </xs:sequence>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

4.1.6 Sample Data for Q3

The content of term_def_list.xml is:

<doc>
  <dt>XML</dt>
  <dd>Extensible Markup Language</dd>
  <dt>XSLT</dt>
  <dt>XSL Transformations</dt>
  <dd>A language for transforming XML</dd>
  <dd>A specification produced by W3C</dd>
</doc>

4.1.7 XML Schema for Q4-Q6

Q4 - Q6 use an input document named temp_events.xml, with the following XML Schema named temp_events.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="stream">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="event" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:attribute name="time" type="xs:integer" use="required"/>
                        <xs:attribute name="temp" type="xs:double" use="required"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

4.1.8 Sample Data for Q4-Q6

The content of temp_events.xml is:

<stream>
  <event temp="10" time="1"/>
  <event temp="8" time="2"/>
  <event temp="6" time="3"/>
  <event temp="13" time="4"/>
  <event temp="32" time="5"/>
  <event temp="9" time="6"/>
  <event temp="10" time="7"/>
</stream>

4.1.9 XML Schema for Q7-Q13

Q7 - Q13 use an input document named person_events.xml, with the following XML Schema named person_events.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="stream">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="event" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence minOccurs="0">
                            <xs:element name="person" type="xs:string"/>
                            <xs:element name="direction" type="xs:string"/>
                        </xs:sequence>
                        <xs:attribute name="time" type="xs:dateTime" use="required"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

4.1.10 Sample Data for Q7-Q13

The content of person_events.xml is:

<stream>
  <event time="2006-01-01T01:00:00-00:00"/>
  <event time="2006-01-01T10:30:00-00:00">
    <person>Anton</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-01T11:00:00-00:00">
    <person>Barbara</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-01T11:15:00-00:00">
    <person>Clara</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-01T12:15:00-00:00">
    <person>Clara</person>
    <direction>out</direction>
  </event>
  <event time="2006-01-01T14:00:00-00:00">
    <person>Barbara</person>
    <direction>out</direction>
  </event>
  <event time="2006-01-01T15:00:00-00:00">
    <person>Anton</person>
    <direction>out</direction>
  </event>
  <event time="2006-01-01T23:00:00-00:00"/>
  <event time="2006-01-02T01:00:00-00:00"/>
  <event time="2006-01-02T11:00:00-00:00">
    <person>Anton</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-02T12:00:00-00:00">
    <person>Clara</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-02T12:10:00-00:00">
    <person>Clara</person>
    <direction>out</direction>
  </event>
  <event time="2006-01-02T12:15:00-00:00">
    <person>Clara</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-02T12:20:00-00:00">
    <person>Clara</person>
    <direction>out</direction>
  </event>
    <event time="2006-01-02T12:25:00-00:00">
    <person>Clara</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-02T12:40:00-00:00">
    <person>Clara</person>
    <direction>out</direction>
  </event>
  <event time="2006-01-02T14:00:00-00:00">
    <person>Clara</person>
    <direction>in</direction>
  </event>
  <event time="2006-01-02T16:00:00-00:00">
    <person>Anton</person>
    <direction>out</direction>
  </event>
  <event time="2006-01-02T16:15:00-00:00">
    <person>Clara</person>
    <direction>out</direction>
  </event>
  <event time="2006-01-02T23:00:00-00:00"/>
</stream>

4.1.11 XML Schema for Q14-Q16

Q14 - Q16 use as input document a slightly modified RSS document named rss.xml. It mainly differs from RSS 2.0 in the way dates are expressed in the data. The XML Schema, rss.xsd, is as follows:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="rss">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="channel">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="title" type="xs:string"/>
                            <xs:element name="link" type="xs:anyURI"/>
                            <xs:element name="description" type="xs:string"/>
                            <xs:element name="language" type="xs:string"/>
                            <xs:element ref="item" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="item">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="title" type="xs:string"/>
                <xs:element name="category" type="xs:string"/>
                <xs:element name="author" type="xs:string"/>
                <xs:element name="pubDate" type="xs:dateTime"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

4.1.12 Sample Data for Q14-Q16

The content of rss.xml is:

<rss>
  <channel>
    <title>DBIS RSS</title>
    <link>http://www.dbis.ethz.ch</link>
    <description>The windowing dummy RSS.</description>
    <language>en-us</language>
    <item>
      <title>Why use cases are important Part 1.</title>
      <category>Workshop</category>
      <author>[email protected]</author>
      <pubDate>2003-06-03T09:00:00</pubDate>
    </item>
    <item>
      <title>Why use cases are important Part 2.</title>
      <category>Workshop</category>
      <author>[email protected]</author>
      <pubDate>2003-06-03T09:00:00</pubDate>
    </item>
    <item>
      <title>Why use cases are important Part 3.</title>
      <category>Workshop</category>
      <author>[email protected]</author>
      <pubDate>2003-06-03T10:00:00</pubDate>
    </item>
    <item>
      <title>Extending XQuery with Window Functions</title>
      <category>Talk</category>
      <author>[email protected]</author>
      <pubDate>2003-06-03T11:00:00</pubDate>
    </item>
    <item>
      <title>XQueryP: A new programming language is born</title>
      <category>Talk</category>
      <author>[email protected]</author>
      <pubDate>2003-06-03T12:00:00</pubDate>
    </item>
    <item>
      <title>Why use cases are annoying to write.</title>
      <category>Talk</category>
      <author>[email protected]</author>
      <pubDate>2003-06-04T10:00:00</pubDate>
    </item>
  </channel>
</rss>

4.1.13 XML Schema for Q17-Q19

Q17-Q19 use an input document named cxml.xml. The structure of this document is inspired by the Commerce XML Resource standard (cXML). The document contains a sequence of events, where an event corresponds to a simplified message of the cXML standard or an timeclock event. The XML Schema with the file-name cxml.xsd is as follows:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="sequence">
        <xs:complexType>
            <xs:sequence>
                <xs:choice maxOccurs="unbounded">
                    <xs:element name="time" type="TimeEvent"/>
                    <xs:element name="OrderRequest" type="OrderRequest" maxOccurs="unbounded"/>
                    <xs:element name="ConfirmationRequest" type="ConfirmationRequest"/>
                    <xs:element name="ShipNotice" type="ShipNotice" maxOccurs="unbounded"/>
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="TimeEvent">
        <xs:attribute name="date" type="xs:dateTime" use="required"/>
    </xs:complexType>
    <xs:complexType name="OrderRequest">
        <xs:sequence>
            <xs:element name="Item" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:attribute name="unitPrice" type="xs:byte" use="required"/>
                    <xs:attribute name="quantity" type="xs:byte" use="required"/>
                    <xs:attribute name="partID" type="xs:string" use="required"/>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
        <xs:attribute name="type" type="xs:string" use="required"/>
        <xs:attribute name="total" type="xs:short" use="required"/>
        <xs:attribute name="shipTo" type="xs:string"/>
        <xs:attribute name="orderID" type="xs:string" use="required"/>
        <xs:attribute name="date" type="xs:dateTime" use="required"/>
        <xs:attribute name="billTo" type="xs:string" use="required"/>
    </xs:complexType>
    <xs:complexType name="ConfirmationRequest">
        <xs:attribute name="status" type="xs:string" use="required"/>
        <xs:attribute name="orderID" type="xs:string" use="required"/>
        <xs:attribute name="date" type="xs:dateTime" use="required"/>
        <xs:attribute name="confirmID" type="xs:string" use="required"/>
    </xs:complexType>
    <xs:complexType name="ShipNotice">
        <xs:attribute name="orderID" type="xs:string" use="required"/>
        <xs:attribute name="date" type="xs:dateTime" use="required"/>
    </xs:complexType>
</xs:schema>

4.1.14 Sample Data for Q17-Q19

The content of cxml.xml is:

<sequence>
  <time date="2006-01-01T00:00:00-00:00"/>
  <OrderRequest billTo="ACME1" date="2006-01-01T10:00:00-00:00"
    orderID="OID01" shipTo="ACME1" total="1100" type="new">
    <Item partID="ID1" quantity="10" unitPrice="100"/>
    <Item partID="ID2" quantity="10" unitPrice="10"/>
  </OrderRequest>
  <OrderRequest billTo="ACME2" date="2006-01-01T11:00:00-00:00"
    orderID="OID02" total="100" type="new">
    <Item partID="ID2" quantity="10" unitPrice="10"/>
  </OrderRequest>
  <ConfirmationRequest confirmID="C1" date="2006-01-01T18:00:00-00:00"
    orderID="OID02" status="reject"/>
  <time date="2006-01-02T00:00:00-00:00"/>
  <ConfirmationRequest confirmID="C1" date="2006-01-02T08:00:00-00:00"
    orderID="OID01" status="accept"/>
  <OrderRequest billTo="ACME1" date="2006-01-02T14:00:00-00:00"
    orderID="OID03" shipTo="ACME1" total="10000" type="new">
    <Item partID="ID3" quantity="100" unitPrice="100"/>
  </OrderRequest>
  <ConfirmationRequest confirmID="C1" date="2006-01-02T16:00:00-00:00"
    orderID="OID03" status="accept"/>
  <time date="2006-01-03T00:00:00-00:00"/>
  <time date="2006-01-04T00:00:00-00:00"/>
  <time date="2006-01-05T00:00:00-00:00"/>
  <ShipNotice date="2006-01-05T08:00:00-00:00" orderID="OID01"/>
  <ShipNotice date="2006-01-05T09:00:00-00:00" orderID="OID03"/>
  <time date="2006-01-06T00:00:00-00:00"/>
  <OrderRequest billTo="ACME2" date="2006-01-06T08:00:00-00:00"
    orderID="OID04" total="100" type="new">
    <Item partID="ID2" quantity="10" unitPrice="10"/>
  </OrderRequest>
  <time date="2006-01-07T00:00:00-00:00"/>
</sequence>

4.2 Queries and Results

4.2.1 Q1

Arrange a sequence of items as a table with three columns (using as many rows as necessary).

Solution in XQuery:

declare variable $seq := fn:doc("arrange_rows.xml");

<table>{
  for tumbling window $w in $seq/doc/*
    start at $x when fn:true()
    end at $y when $y - $x = 2
  return
    <tr>{
      for $i in $w
      return
        <td>{data($i)}</td>
    }</tr>
}</table>

Expected Result:

<table>
  <tr>
    <td>Green</td>
    <td>Pink</td>
    <td>Lilac</td>
  </tr>
  <tr>
    <td>Turquoise</td>
    <td>Peach</td>
    <td>Opal</td>
  </tr>
  <tr>
    <td>Champagne</td>
  </tr>
</table>

4.2.2 Q2

Convert a structure with implicit sections to a structure with explicit sections.

Solution in XQuery:

declare variable $seq := fn:doc("head_para.xml");

<chapter>{
  for tumbling window $w in $seq/body/*
    start previous $s when $s[self::h2]
    end next $e when $e[self::h2]
  return
    <section title="{data($s)}">{
       for $x in $w
       return
         <para>{data($x)}</para>
  }</section>
}</chapter>

Expected Result:

<chapter>
  <section title="heading1">
    <para>para1</para>
    <para>para2</para>
  </section>
  <section title="heading2">
    <para>para3</para>
    <para>para4</para>
    <para>para5</para>
  </section>
</chapter>

4.2.3 Q3

Within a glossary in HTML, a defined term <dt> can be followed by a definition <dd>. The task is to group these together within a <term> element, where a group can consist of one or more <dt> elements followed by one or more <dd> elements.

Solution in XQuery:

declare variable $seq := fn:doc("term_def_list.xml");

<doc>{
for tumbling window $w in $seq/doc/*
  start $x when $x[self::dt]
  end $y next $z when $y[self::dd] and $z[self::dt]
return
  <term>{
    $w
  }</term>
}</doc>

Expected Result:

<doc>
  <term>
    <dt>XML</dt>
    <dd>Extensible Markup Language</dd>
  </term>
  <term>
    <dt>XSLT</dt>
    <dt>XSL Transformations</dt>
    <dd>A language for transforming XML</dd>
    <dd>A specification produced by W3C</dd>
  </term>
</doc>

4.2.4 Q4

Calculate the moving average of temperature values for the 3 last seconds.

Solution in XQuery:

declare variable $timesequence := fn:doc("temp_events.xml");

let $MAX_DIFF := 2

for sliding window $w in $timesequence/stream/event
  start  $s_curr at $s_pos previous $s_prev
    when ($s_curr/@time ne $s_prev/@time) or (empty($s_prev))
  only end next $e_next
    when $e_next/@time - $s_curr/@time gt $MAX_DIFF
return
  avg( $w/@temp )

Expected Result:

8 9 17 18

4.2.5 Q5

Single exponential smoothing (3 last values and smoothing factor 0.2)

Solution in XQuery:

declare variable $timesequence := fn:doc("temp_events.xml");
let $SMOOTH_CONST := 0.2

for sliding window $w in $timesequence/stream/event
  start at $s_pos when true()
  only end at $e_pos when $e_pos - $s_pos eq 2
return
  round-half-to-even($SMOOTH_CONST * data($w[3]/@temp) + (1 - $SMOOTH_CONST) *
    ( $SMOOTH_CONST * data($w[2]/@temp) +
      (1 - $SMOOTH_CONST) * data($w[1]/@temp) ), 2)

Expected Result:

8.88 8.68 12.32 15.24 23.92

4.2.6 Q6

Detect outliers (current value is two times higher (lower) than the average of the previous three values) in a sequence of temp values.

Solution in XQuery:

declare variable $seq := fn:doc("temp_events.xml");

for sliding window $w in $seq/stream/event
  start  $s_curr when fn:true()
  only end next $next when $next/@time > $s_curr/@time + 3
return
  let $avg := fn:avg($w/@temp)
  where $avg * 2 lt xs:double($next/@temp) or $avg div 2 gt xs:double($next/@temp)
  return <alarm>Outlier detected. Event id:{data($next/@time)}</alarm>

Expected Result:

<alarm>Outlier detected. Event id:5</alarm>

4.2.7 Q7

Notify when Barbara enters the building within 1 hour after Anton

Solution in XQuery:

declare variable $seq := fn:doc("person_events.xml");

<result>{
  for tumbling window $w in $seq/stream/event
    start  $s when $s/person eq "Anton" and $s/direction eq "in"
    only end $e next $n when  xs:dateTime($n/@time) - xs:dateTime($s/@time) gt
      xs:dayTimeDuration("PT1H")
      or  ($e/person eq "Barbara" and $e/direction eq "in")
      or ($e/person eq "Anton" and $e/direction eq "out")
  where $e/person eq "Barbara" and $e/direction eq "in"
  return
    <warning time="{ $e/@time }">Barbara: Anton arrived 1h ago</warning>
}</result>

Expected Result:

<result>
  <warning time="2006-01-01T11:00:00-00:00">Barbara: Anton arrived 1h ago</warning>
</result>

4.2.8 Q8

Measure the working time of each person

Solution in XQuery:

declare variable $seq := fn:doc("person_events.xml");

<result>{
for sliding window $w in $seq/stream/event
  start  $s when $s/direction eq "in"
  only end  $e when $s/person eq $e/person and
    $e/direction eq "out"
return
  <working-time>
      {$s/person}
      <time>{ xs:dateTime($e/@time) - xs:dateTime($s/@time)}</time>
  </working-time>
}</result>

Expected Result:

<result>
        <working-time>
                <person>Anton</person>
                <time>PT4H30M</time>
        </working-time>
        <working-time>
                <person>Barbara</person>
                <time>PT3H</time>
        </working-time>
        <working-time>
                <person>Clara</person>
                <time>PT1H</time>
        </working-time>
        <working-time>
                <person>Anton</person>
                <time>PT5H</time>
        </working-time>
        <working-time>
                <person>Clara</person>
                <time>PT10M</time>
        </working-time>
        <working-time>
                <person>Clara</person>
                <time>PT5M</time>
        </working-time>
        <working-time>
                <person>Clara</person>
                <time>PT15M</time>
        </working-time>
        <working-time>
                <person>Clara</person>
                <time>PT2H15M</time>
        </working-time>
</result>

4.2.9 Q9

Measure the overall working time for each person.

Solution in XQuery:

declare variable $seq := fn:doc("person_events.xml");

<result>{
for sliding window $w in $seq/stream/event
  start  $s when $s/direction eq "in"
  only end  $e when $s/person eq $e/person and
    $e/direction eq "out"
let $person := $s/person
let $workingTime := xs:dateTime($e/@time) - xs:dateTime($s/@time)
group by $person
order by $person
return
  <working-time>
    <person>{ $person }</person>
    <time>{ sum($workingTime) }</time>
  </working-time>
}</result>

Expected Result:

<result>
  <working-time>
    <person>Anton</person>
    <time>PT9H30M</time>
  </working-time>
  <working-time>
    <person>Barbara</person>
    <time>PT3H</time>
  </working-time>
  <working-time>
    <person>Clara</person>
    <time>PT3H45M</time>
  </working-time>
</result>

4.2.10 Q10

Display a warning if Barbara does not come to work.

Solution in XQuery:

declare variable $seq := fn:doc("person_events.xml");

<result>{
  for tumbling window $w in $seq/stream/event[direction eq "in"]
    start  $s when fn:true()
    end next $e when xs:date( xs:dateTime($s/@time) ) ne xs:date( xs:dateTime($e/@time) )
  let $date := xs:date(xs:dateTime($s/@time))
  where not($w[person eq "Barbara"])
  return <alert date="{ $date }">Barbara did not come to work</alert>
}</result>

Expected Result:

<result>
  <alert date="2006-01-02Z">Barbara did not come to work</alert>
</result>

4.2.11 Q11

Identify every person who enters the building before Clara withing a 15 minute timeframe (Clara's arrival time - 15 minutes).

Solution in XQuery:

declare variable $seq := fn:doc("person_events.xml");

<results>{
  for tumbling window $w in $seq/stream/event[direction eq "in"]
    start when true()
    only end next $x when  $x/person eq "Clara"
  return
    <result time="{ $x/@time }">{
      distinct-values(for $y in $w
        where (xs:dateTime($y/@time) + xs:dayTimeDuration("PT15M") ) ge xs:dateTime($x/@time)
        return $y/person)
    }</result>
}</results>

Expected Result:

<results>
        <result time="2006-01-01T11:15:00-00:00">Barbara</result>
        <result time="2006-01-02T12:00:00-00:00"/>
        <result time="2006-01-02T12:15:00-00:00">Clara</result>
        <result time="2006-01-02T12:25:00-00:00">Clara</result>
        <result time="2006-01-02T14:00:00-00:00"/>
</results>

4.2.12 Q12

Notify when both Anton and Barbara enter the office within 30 minutes of one another.

Solution in XQuery:

declare variable $seq := fn:doc("person_events.xml");

<result>{
        for tumbling window $w in $seq/stream/event[direction eq "in"]
                start  $x when $x/person = ("Barbara", "Anton")
                end next $y when xs:dateTime($y/@time) - xs:dateTime($x/@time) gt xs:dayTimeDuration("PT30M")
        where $w[person eq "Anton"] and $w[person eq "Barbara"]
        return
                <alert time="{ xs:dateTime($y/@time) }">Anton and Barbara just arrived</alert>
}</result>

Expected Result:

<result>
        <alert time="2006-01-01T11:15:00Z">Anton and Barbara just arrived</alert>
</result>

4.2.13 Q13

Inform when a person enters the building at least 3 times within 1 hour

Solution in XQuery:

declare variable $seq := fn:doc("person_events.xml");

<result>{
  for sliding window $w in $seq/stream/event
    start  $s when true()
    end next $e when xs:dateTime($e/@time) - xs:dateTime($s/@time) gt
      xs:dayTimeDuration("PT1H")
  where count($w[person eq $s/person and direction eq "in"]) ge 3
  return
    <alert time="{ $e/@time }">{fn:data($s/person)} is suspicious</alert>
}</result>

Expected Result:

<result>
  <alert time="2006-01-02T14:00:00-00:00">Clara is suspicious</alert>
</result>

4.2.14 Q14

Find all annoying authors who have posted three consecutive items in the RSS feed.

Solution in XQuery:

declare variable $rssfeed := fn:doc("rss.xml");

<result>{
  for tumbling window $w in $rssfeed/rss/channel/item
    start  $first when fn:true()
    end next $lookAhead when $first/author ne $lookAhead/author
  where count($w) ge 3
  return <annoying-author>{
      $w[1]/author
    }</annoying-author>
}</result>

Expected Result:

<result>
  <annoying-author>
    <author>[email protected]</author>
  </annoying-author>
</result>

4.2.15 Q15

Every day, provide a list of interesting topics in the RSS feed. In our example, interesting means that the title of the item contains the specific word XQuery.

Solution in XQuery:

declare variable $rssfeed := fn:doc("rss.xml");

<result>{
  for tumbling window $w in $rssfeed/rss/channel/item
    start  $s_curr when true()
    end next $e_next when
      fn:day-from-dateTime(xs:dateTime($e_next/pubDate)) ne
      fn:day-from-dateTime(xs:dateTime($s_curr/pubDate))
  return
    <item>
        <date>{xs:date(xs:dateTime($s_curr/pubDate))}</date>
        {  for $item in $w
                   where fn:contains( xs:string($item/title), 'XQuery')
                   return $item/title   }
      </item>
}</result>

Expected Result:

<result>
  <item>
    <date>2003-06-03</date>
    <title>Extending XQuery with Window Functions</title>
    <title>XQueryP: A new programming language is born</title>
  </item>
  <item>
    <date>2003-06-04</date>
  </item>
</result>

4.2.16 Q16

Every day, provide a summary of the RSS feed grouped by author.

Solution in XQuery:

declare variable $rssfeed := fn:doc("rss.xml");

<result>{
  for tumbling window $w in $rssfeed/rss/channel/item
    start  $s_curr when true()
    end next $e_next when
      fn:day-from-dateTime(xs:dateTime($e_next/pubDate)) ne
      fn:day-from-dateTime(xs:dateTime($s_curr/pubDate))
  return
    <item>
      <date>{xs:date(xs:dateTime($s_curr/pubDate))}</date>
       {  for $a in fn:distinct-values($w/author)
           return
             <author name="{$a}">
               <titles>
                 { $w[author eq $a]/title }
               </titles>
                        </author>
            }
          </item>
}</result>

Expected Result:

<result>
  <item>
    <date>2003-06-03</date>
    <author name="[email protected]">
      <titles>
        <title>Why use cases are important Part 1.</title>
        <title>Why use cases are important Part 2.</title>
        <title>Why use cases are important Part 3.</title>
      </titles>
    </author>
    <author name="[email protected]">
      <titles>
        <title>Extending XQuery with Window Functions</title>
      </titles>
    </author>
    <author name="[email protected]">
      <titles>
        <title>XQueryP: A new programming language is born</title>
      </titles>
    </author>
  </item>
  <item>
    <date>2003-06-04</date>
    <author name="[email protected]">
      <titles>
        <title>Why use cases are annoying to write.</title>
      </titles>
    </author>
  </item>
</result>

4.2.17 Q17

At the end of a day, list the most valuable customers.

Solution in XQuery:

declare variable $seq := fn:doc("cxml.xml");

<result>{
for sliding window $w in $seq/sequence/*
  start  $cur previous $prev
   when day-from-dateTime($cur/@date) ne day-from-dateTime($prev/@date) or empty($prev)
  end $end next $next
   when day-from-dateTime(xs:dateTime($end/@date)) ne
day-from-dateTime(xs:dateTime($next/@date))
return
  <mostValuableCustomer endOfDay="{xs:dateTime($cur/@date)}">{
    let $companies :=   for $x in distinct-values($w/@billTo )
                        return <amount company="{$x}">{sum($w[@billTo eq $x]/@total)}</amount>
    let $max := max($companies)
    for $company in $companies
    where $company eq xs:untypedAtomic($max)
    return $company
  }</mostValuableCustomer>
}</result>

Expected Result:

<result>
  <mostValuableCustomer endOfDay="2006-01-01T00:00:00Z">
    <amount company="ACME1">1100</amount>
  </mostValuableCustomer>
  <mostValuableCustomer endOfDay="2006-01-02T00:00:00Z">
    <amount company="ACME1">10000</amount>
  </mostValuableCustomer>
  <mostValuableCustomer endOfDay="2006-01-03T00:00:00Z"/>
  <mostValuableCustomer endOfDay="2006-01-04T00:00:00Z"/>
  <mostValuableCustomer endOfDay="2006-01-05T00:00:00Z"/>
  <mostValuableCustomer endOfDay="2006-01-06T00:00:00Z">
    <amount company="ACME2">100</amount>
  </mostValuableCustomer>
  <mostValuableCustomer endOfDay="2006-01-07T00:00:00Z"/>
</result>

4.2.18 Q18

Calculate the time needed to process an order from the request up to the shipping.

Solution in XQuery:

declare variable $seq := fn:doc("cxml.xml");

<result>{
  for sliding window $w in $seq/sequence/*
    start $s when $s[self::OrderRequest]
    end   $e when $e/@orderID eq  $s/@orderID
             and ($e[self::ConfirmationRequest] and $e/@status eq "reject"
                  or $e[self::ShipNotice])
  where $e[self::ShipNotice]
  return
    <timeToShip orderID="{ $s/@orderID}">{xs:dateTime($e/@date) - xs:dateTime($s/@date) }</timeToShip>
}</result>

Expected Result:

<result>
  <timeToShip orderID="OID01">P3DT22H</timeToShip>
  <timeToShip orderID="OID03">P2DT19H</timeToShip>
</result>

4.2.19 Q19

At the moment of the shipping notification, calculate if an open request exists that can be shipped to the same address.

Solution in XQuery:

declare variable $seq := fn:doc("cxml.xml");

<result>{
  for sliding window $w in $seq/sequence/*
    start previous $wSPrev when $wSPrev[self::OrderRequest]
    end next $wENext when $wENext/@orderID eq  $wSPrev/@orderID
        and ($wENext[self::ConfirmationRequest] and $wENext/@status eq "reject"
                 or $wENext[self::ShipNotice])
  where $wENext[self::ShipNotice]
  return
    <bundleWith orderId="{$wSPrev/@orderID}">{
        for sliding window $bundle in $w
          start  $bSCur
            when $bSCur[self::OrderRequest] and $bSCur/@shipTo eq $wSPrev/@shipTo
          end  $bECur next $bENext
            when $bECur/@orderID eq  $bSCur/@orderID
             and ($bECur[self::ConfirmationRequest] and $bECur/@status eq "reject"
              or $bECur[self::ShipNotice])
          where empty($bENext)
          return $bSCur
    }</bundleWith>
}</result>

Expected Result:

<result>
  <bundleWith orderId="OID01">
    <OrderRequest billTo="ACME1" date="2006-01-02T14:00:00-00:00"
      orderID="OID03" shipTo="ACME1" total="10000" type="new">
      <Item partID="ID3" quantity="100" unitPrice="100"/>
    </OrderRequest>
  </bundleWith>
  <bundleWith orderId="OID03"/>
</result>

5 Use Case "Count" - Queries which require output numbering

The described queries in this section all require tuple numbering. The numbering is either required in the final result or might also be required at some point in the middle when the tuple stream gets generated.

5.1 Schema and Sample Data

The "Count" use cases are all based on the shopping scenario which can be found in the section Shopping Scenario Schema and Data.

5.2 Queries and Results

5.2.1 Q1

List all products in alphabatical order with a continously increasing number.

Solution in XQuery:

<products>{
    for $product in doc("products.xml")/*/product
    order by $product/name
    count $number
    return
        <product number="{$number}">{$product/*}</product>
}</products>

Expected Result:

<products>
    <product number="1">
        <name>blender</name>
        <category>kitchen</category>
        <price>50</price>
        <cost>25</cost>
    </product>
    <product number="2">
        <name>broiler</name>
        <category>kitchen</category>
        <price>100</price>
        <cost>70</cost>
    </product>
    <product number="3">
        <name>shirt</name>
        <category>clothes</category>
        <price>10</price>
        <cost>3</cost>
    </product>
    <product number="4">
        <name>socks</name>
        <category>clothes</category>
        <price>5</price>
        <cost>2</cost>
    </product>
    <product number="5">
        <name>toaster</name>
        <category>kitchen</category>
        <price>30</price>
        <cost>10</cost>
    </product>
</products>

5.2.2 Q2

Arrange a sequence of items as a table with three columns (using as many rows as necessary) like in Q1 from the windowing use cases.Additionally, number every row continuously.

Solution in XQuery:

declare variable $seq := fn:doc("arrange_rows.xml");

<table>{
  for tumbling  window $w in $seq/doc/*
    start at $x when fn:true()
    end at $y when $y - $x = 2
  count $rowNumber
  return
    <tr>
      <td>{$rowNumber}</td>{
      for $i in $w
      return
        <td>{data($i)}</td>
    }</tr>
}</table>

Expected Result:

<table>
    <tr>
        <td>1</td>
        <td>Green</td>
        <td>Pink</td>
        <td>Lilac</td>
    </tr>
    <tr>
        <td>2</td>
        <td>Turquoise</td>
        <td>Peach</td>
        <td>Opal</td>
    </tr>
    <tr>
        <td>3</td>
        <td>Champagne</td>
    </tr>
</table>

5.2.3 Q3

Top-K query: Return the three best-selling products (by quantity).

Solution in XQuery:

<result>{
    for $sales in doc("sales-records.xml")/*/record
    let $name := $sales/product-name
    group by $name
    let $qty := sum($sales/qty)
    order by $qty descending
    count $count
    where $count <= 3
    return
        <sale product="{$name}" qty="{$qty }"/>
}</result>

Expected Result:

<result>
    <sale product="socks" qty="510"/>
    <sale product="blender" qty="250"/>
    <sale product="toaster" qty="200"/>
</result>

6 Use Case "Outer For" - Queries which require outer joins

This use case demonstrate how the new "outer for" clause can help to express outer joins in XQuery.

6.1 Schema and Sample Data

The "Outer For" use case is based on the shopping scenario which can be found in the section Shopping Scenario Schema and Data.

6.2 Queries and Results

6.2.1 Q1

Report all the store sales including stores which have not sold anything.

Solution in XQuery:

<result>{
    for $store in doc("stores.xml")/*/store
    for $sale allowing empty in doc("sales-records.xml")/*/record[
         store-number eq $store/store-number]
    return
      <store number="{$store/store-number}"
         product="{$sale/product-name}"
         state="{$store/state}"
         sold="{$sale/qty}" />
}</result>

Expected Result:

<result>
    <store number="1" state="CA" product="broiler" sold="20"/>
    <store number="1" state="CA" product="socks" sold="500"/>
    <store number="2" state="CA" product="toaster" sold="100"/>
    <store number="2" state="CA" product="toaster" sold="50"/>
    <store number="2" state="CA" product="socks" sold="10"/>
    <store number="3" state="MA" product="toaster" sold="50"/>
    <store number="3" state="MA" product="blender" sold="100"/>
    <store number="3" state="MA" product="blender" sold="150"/>
    <store number="3" state="MA" product="shirt" sold="10"/>
    <store number="4" state="WA" product="" sold=""/>
</result>

6.2.2 Q2

List all the sales records. Include also all the items which were not sold in a store.

Solution in XQuery:

<result>{
for $store in doc("stores.xml")/*/store
for $product in doc("products.xml")/*/product
for $sale allowing empty in doc("sales-records.xml")/*/record[
     store-number eq $store/store-number and
     product-name eq $product/name]
return
  <store number="{$store/store-number}"
      state="{$store/state}"
      product="{$sale/product-name}"
      sold="{$sale/qty}" />
}</result>

Expected Result:

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <store number="1" state="CA" product="broiler" sold="20"/>
    <store number="1" state="CA" product="toaster" sold=""/>
    <store number="1" state="CA" product="blender" sold=""/>
    <store number="1" state="CA" product="socks" sold="500"/>
    <store number="1" state="CA" product="shirt" sold=""/>
    <store number="2" state="CA" product="broiler" sold=""/>
    <store number="2" state="CA" product="toaster" sold="100"/>
    <store number="2" state="CA" product="toaster" sold="50"/>
    <store number="2" state="CA" product="blender" sold=""/>
    <store number="2" state="CA" product="socks" sold="10"/>
    <store number="2" state="CA" product="shirt" sold=""/>
    <store number="3" state="CA" product="broiler" sold=""/>
    <store number="3" state="MA" product="toaster" sold="50"/>
    <store number="3" state="MA" product="blender" sold="100"/>
    <store number="3" state="MA" product="blender" sold="150"/>
    <store number="3" state="MA" product="socks" sold=""/>
    <store number="3" state="MA" product="shirt" sold="10"/>
    <store number="4" state="MA" product="broiler" sold=""/>
    <store number="4" state="MA" product="toaster" sold=""/>
    <store number="4" state="MA" product="blender" sold=""/>
    <store number="4" state="MA" product="socks" sold=""/>
    <store number="4" state="MA" product="shirt" sold=""/>
</result>

7 Use Case "Try-Catch" - Queries which require to recover from errors

This use case covers queries that require to recover from errors.

7.1 Sample Data

Q1 and Q2 are based on a errornous version of product.xml from Shopping Scenario Schema and Data, whereas Q3 does not require any input data. Sample data for Q1 and Q2 named product-err.xml are shown below:

<products>
  <product>
    <name>broiler</name>
    <category>kitchen</category>
    <price>100</price>
    <cost>"70"</cost>
  </product>
  <product>
    <name>toaster</name>
    <category>kitchen</category>
    <price>30</price>
    <cost>10</cost>
  </product>
  <product>
    <name>blender</name>
    <category>kitchen</category>
    <price>50</price>
    <cost>25</cost>
  </product>
  <product>
    <name>socks</name>
    <category>clothes</category>
    <price>5</price>
    <cost>2</cost>
  </product>
  <product>
    <name>shirt</name>
    <category>clothes</category>
    <price>10</price>
    <cost>3</cost>
  </product>
</products>

7.2 Queries and Results

7.2.1 Q1

Calculate the margin of every product. If an error occurs, report a user-friendly message.

Solution in XQuery:

try {
    <result>{
        for $product in fn:doc("product-err.xml")//product
        return
            <product>{$product/name}
            <margin>{$product/price - $product/cost}</margin>
            </product>
    }</result>
} catch * {
     "An error occured, please ask your consultant for help."
}

Expected Result:

An error occured, please ask your consultant for help.

7.2.2 Q2

Report the margin in procent of every product. If an error occurs the failure should be listed, but the query should still continue to report the other values.

Solution in XQuery:

<result>{
    for $product in fn:doc("product-err.xml")//product
    return
         try {
            <product>{$product/name}
              <margin>{$product/price div $product/cost}</margin>
            </product>
        } catch * {
            <product>{
                ($product/name, "Error:", $err:code)
            }</product>
        }
}</result>

Expected Result:

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <product>
        <name>broiler</name>
        Error: FORG0001
    </product>
    <product>
        <name>toaster</name>
        <margin>3</margin>
    </product>
    <product>
        <name>blender</name>
        <margin>2</margin>
    </product>
    <product>
        <name>socks</name>
        <margin>2.5</margin>
    </product>
    <product>
        <name>shirt</name>
        <margin>3.3333333333333333</margin>
    </product>
</result>

7.2.3 Q3

For a sequence of inputs the n-th fibonacci number has to be calculated using a pre-defined function. The function is built to avoid long running times and therefore rejects high values by throwing a user-defined error. If such an error occurs during calculation, a warning should be displayed, but the processing should continue.

Solution in XQuery:

declare namespace foo='http://foo.com';
declare function local:fib-recur($n as xs:integer) as xs:integer? {
    if ($n <0) then ()
    else if ($n > 100) then
        fn:error(fn:QName('http://foo.com', 'ValueToBig'), 'Value too big')
    else if ($n = 0)  then 0
    else if ($n=1)   then 1
    else local:fib-recur($n - 1)  + local:fib-recur($n - 2)
};

<result>{
    for $x in (3,1,1030,5)
    return
        try{
        <fib input="{$x}">{local:fib-recur($x)}</fib>
        }catch foo:ValueToBig {
          <fib input="{$x}">Number to big</fib>
        }
}</result>

Expected Result:

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <fib input="3">2</fib>
    <fib input="1">1</fib>
    <fib input="1030">Number to big</fib>
    <fib input="5">5</fib>
</result>

A Acknowledgements (Non-Normative)

The Working Group thanks the following individuals for their contributions:

Peter M. Fischer, Donald Kossmann, Rokas Tamosevicius Use Case "windowing"

B Change Log (Non-Normative)

B.1 30 Mar 2011

  • Removed xsi declaration and xsi:noNamespaceSchemaLocation attributes in input documents. Resolves BZ 11757.

  • Corrected input file name in Windowing Q7. Resolves BZ 11756.

  • Corrected Clara's working time in Windowing Q8. Resolves BZ 11758.

  • Added order by $person to Windowing Q9. Resolves BZ 11759.

  • Corrected Clara's working time in Windowing Q9. Resolves BZ 11853.

  • Corrected result of Windowing Q12. Resolves BZ 11761.

  • Added parentheses to correct solutions in Windowing Q18 and Q19. Resolves BZ 11762.

B.2 30 January 2008

  • Added group-by UC.

  • Added windowing UC.

B.3 17 November 2008

  • Added try-catch UC.

  • Added outer-join UC.

  • Added output-numbering UC.

  • Changed all DTDs to XML Schema.

C References (Non-Normative)

The following references are some of the works considered by the WG in deriving its use cases.

XMLSchema0
XML Schema Part 0: Primer Second Edition, David Fallside and Priscilla Walmsley, Editors. World Wide Web Consortium, 28 Oct 2004. This version is http://www.w3.org/TR/2004/REC-xmlschema-0-20041028/. The latest version is available at http://www.w3.org/TR/xmlschema-0/.
XMLSchema1
XML Schema Part 1: Structures Second Edition, Henry Thompson, David Beech, Murray Maloney, and Noah Mendelsohn, Editors. World Wide Web Consortium, 28 Oct 2004. This version is http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/. The latest version is available at http://www.w3.org/TR/xmlschema-1/.
XMLSchema2
XML Schema Part 2: Datatypes Second Edition, Paul V. Biron and Ashok Malhotra, Editors. World Wide Web Consortium, 28 Oct 2004. This version is http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/. The latest version is available at http://www.w3.org/TR/xmlschema-2/.
XQuery 3.0
XQuery 3.0: An XML Query Language, Jonathan Robie, Don Chamberlin, Michael Dyck, John Snelson, Editors. World Wide Web Consortium, 08 April 2014. This version is http://www.w3.org/TR/2014/REC-xquery-30-20140408/. The latest version is available at http://www.w3.org/TR/xquery-30/.
XQuery 3.0 Requirements
XQuery 3.0 Requirements, Daniel Engovatov, Jonathan Robie, Editors. World Wide Web Consortium, 08 April 2014. This version is http://www.w3.org/TR/2014/NOTE-xquery-30-requirements-20140408/. The latest version is available at http://www.w3.org/TR/xquery-30-requirements/.
XSL Transformations (XSLT) Version 3.0
XSL Transformations (XSLT) Version 3.0, Michael Kay, Editor. World Wide Web Consortium, 12 December 2013. This version is http://www.w3.org/TR/2013/WD-xslt-30-20131212/. The latest version is available at http://www.w3.org/TR/xslt-30/.
Use Case Sample Queries
Queries from this document, presented in a single file