ver the past few years, XML has rapidly gained popularity as a formatting language for information, finding constituencies in both the document-centric and data-centric worlds. The explosive growth of XML-based standards bears testimony to XML’s interest to many different technical communities. Applications now use XML for both transient messages, such as SOAP or XML-RPC messages, and as persistent storage, such as in XML databases or content management systems. An XML-based Web, as opposed to an HTML-based Web, no longer sounds like fantasy.
As the volume of information stored in XML grows, it becomes correspondingly more important to be able to access information in XML documents efficiently and effectively. To do that, you need an expressive query language so you can specify precisely what information you want to retrieve or update in an XML data source. XQuery intends to be that language.
|
This, the first of a four part series introduces you to the XQuery query language. It explains basic XQuery concepts such as the different types of query expressions, the language elements, such as user-defined functions, and illustrates them with example queries.
The Example Scenario
In this article series, you’ll explore important XQuery concepts through series of examples based on a single scenario that will be familiar to most developers. You’ll work with an order-processing application that uses three types of documents: purchase orders po.xml, a customer list customers.xml and an items list items.xml. You can download the sample documents and all the queries from the References column on every page. For readers who are familiar with relational databases, the document po.xml is analogous to a purchase orders table (each record in the table represents a purchase order, just as each
XQuery Overview
XQuery is a query language that lets you retrieve data items from XML-formatted documents. The language is not “complete”? it’s still a work in progress under the auspices of the W3C’s XML Query working group. Nonetheless, implementations of XQuery are already making their way to the market.. The XML Query working group published its latest public XQuery specification working draft on December 20, 2001, and this series is based on that version of the specification.Structure of an XQuery Module
If you’re familiar with other query languages such as SQL, OQL, you’ll notice that XQuery has some similarities, and you’ll probably find some of the syntax to be quite familiar. The term “query module” as used in this article means a “query unit”. You can think of an XQuery module as having three parts (see Figure 1).
- Namespace and Schema Declarations [optional]
- Function Definitions [optional]
- Query Expressions
![]() | |
Figure 1: The three parts of a query module. |
The first two parts together are called the query prolog. The first part can consist of both namespace declarations and schema import statements. The example in Figure 1 defines a namespace prefix xsd mapped to the URI “http://www.w3.org/2000/01/XMLSchema”. The second part contains function definitions. This is the place in a query module to define custom functions. The example in Figure 1 defines a factorial function that accepts an integer parameter and returns its factorial.
The third part of the query contains query expressions. Expressions are the key to XQuery. The example in Figure 1 uses an expression called an Element Constructor, which, as the name suggests, constructs an element named Results. The example invokes the factorial function with a parameter value 10, and the result becomes the content of the Value element.A Quick Look at XQuery Expressions
Every XQuery query contains one or more query expressions.. Some common XQuery expressions are FLWR Expressions, Path Expressions, Element Constructors, Conditional Expressions, and Function Calls.
Here’s a quick look at some of expressions to whet your appetite. Later installments of this series tackle all these expressions in greater detail.
FLWR Expressions
FLWR expressions (pronounced “flower”) are among the most interesting types of expressions in XQuery. Syntactically they look similar to SQL select statements and have similar capabilities. FLWR stands for For-Let-Where-Return, the four clauses that make up an expression of this type. Here’s a sample FLWR expression that retrieves all items from the sample document items.xml that are priced below the average price of all the items.
# See XQuery12.ixq in samples.zip for $i in document("data/items.xml")//item let $avg_price := avg(document("data/items.xml")//item/price) where $i/price < $avg_price return {$i/itemno, $i/description, $i/price}
The for clause binds the variable ‘i’ to the list of item elements from the document items.xml. The let clause computes the average price of all items. The where clause selects all the items priced below the average price, from the items bound by the for clause, and the return clause constructs the LowPricedItem elements which contain the itemno, description and price of the selected items.
|
FLWR expressions are extremely versatile, and you will see more of them in the upcoming parts of this series.
Path Expressions
In XQuery, Path expressions are XPath 2.0 expressions. They use a path notation to select nodes of interest from an XML document. As described in the Data Model section of this series, you can treat an XML document as a tree of nodes. A path expression describes the way to navigate this tree to find the nodes of interest.
For example, the following path expression identifies all item elements that have a parent items element, (which happens to be the document element) in the sample document items.xml.
# see XQuery13.ixq in samples.zip namespace ixq="http://www.ipedo.com/XQueryExample" document("data/items.xml")/ixq:items/item
You can be more selective by introducing predicates (conditions) in a path expression. For example, to find all the items with the itemType “Purchasing item”, you would use the following path expression:
# see XQuery14.ixq in samples.zip namespace ixq="http://www.ipedo.com/XQueryExample" document("data/items.xml")/ixq:items/item[ItemType = "Purchasing item"]
Element Constructors
When writing a query you might sometimes want to create new elements as part of the output. Element constructors are used to provide exactly this functionality. A simple example of an element constructor is :
Hello World
The element constructor shown above constructs an element named newElement, that contains one child text node with the value “Hello World”.
You don’t have to select existing content for new elements, you can create new elements with arbitrary or calculated content. The following element constructor creates an element named “MyListOfExpensiveItems”, containing as its child elements all item elements from the sample document items.xml that are priced over $1000.00.
# see XQuery15.ixq in samples.zip namespace ixq="http://www.ipedo.com/XQueryExample" {document("data/items.xml")/ixq:items/item[price > 1000]}
Whitespace
Whitespace is not significant, with these exceptions:
- Whitespace used in element constructors is preserved.
- Whitespace used in enclosed expressions, for example {expr} is preserved.
- Whitespace is not allowed in path expressions except in the predicate, for example /items/item[name = “scooter”]. The predicate(the part enclosed in square brackets ([]) can contain whitespace, but the rest of the path expression cannot.
Conditional Expressions
A conditional expression takes the form
if then else
In a conditional expression, the condition_expr should evaluate to a Boolean value, or to a type that can be cast to Boolean. If that Boolean value is true, the result of the entire conditional expression is the same as the result of evaluating expr1; otherwise it is the same as the result of evaluating expr2.
Quantified Expressions
A quantified expression uses either an existential quantifier (some) or a universal quantifier (every). Every quantified expression evaluates to a Boolean value. The following examples demonstrate both kinds of quantifiers.
# see XQuery16.ixq in samples.zip # returns purchase orders that only contain # items cheaper than $300 namespace ns = "http://www.ipedo.com/XQueryExample" for $i in document("data/PO.xml")/ns:polist/po where every $p in $i/lineitems/lineitem/item/price satisfies ($p < 300) return $i
The for clause returns all the purchase order elements in the document po.xml. The where clause uses a quantified expression to select only those purchase order elements where the price of every line item is less than $300.
# see XQuery17.ixq in samples.zip #returns all purchase orders which contain at #least one item priced more than $200 namespace ns = "http://www.ipedo.com/XQueryExample" for $i in document("data/PO.xml")/ns:polist/po where some $p in $i/lineitems/lineitem/item/price satisfies ($p > 200) return $i
Like the previous query, the for clause returns all the purchase order elements in document po.xml. This time the where clause uses a quantified expression to select all the purchase orders that have at least one line item priced above $200.00.
Now that you have had a taste of XQuery, you are ready to dive into the XQuery data model, the basic language features, and a more in-depth look at path expressions in Part 2 of this series.