XML XQuery

XQuery is a functional query language purpose-built for extracting, filtering, and reshaping data stored as XML, playing much the same role for XML that SQL plays for relational tables.

What Is XQuery?

XQuery treats an XML document (or a collection of documents) as a queryable tree and lets you ask questions of it directly: which products cost more than $50, sorted by name? which employees report to a given manager? XQuery is built on top of XPath — every XPath expression is a valid XQuery expression — but it adds the ability to construct new XML output, define reusable functions, and combine data from multiple sources in a single query, which is why it's often described as 'SQL for XML.'

FLWOR Expressions

A Basic FLWOR Query

<!DOCTYPE html>
<html>
<body>

<pre>
for $product in doc("catalog.xml")/catalog/product
where $product/price &gt; 20
order by $product/name
return
  &lt;item&gt;
    &lt;name&gt;{ $product/name/text() }&lt;/name&gt;
    &lt;price&gt;{ $product/price/text() }&lt;/price&gt;
  &lt;/item&gt;
</pre>

</body>
</html>

FLWOR — pronounced 'flower' — stands for the five clauses that give the expression its shape: for binds a variable to each item in a sequence, let assigns a computed value, where filters the bound items, order by sorts what's left, and return builds the output for every surviving binding. Only for and return are required; let, where, and order by are optional and can be repeated or omitted as the query demands.

Filtering and Joining Two Documents

<!DOCTYPE html>
<html>
<body>

<pre>
for $order in doc("orders.xml")/orders/order
let $cust := doc("customers.xml")/customers/customer[id = $order/customerId]
where $order/total &gt; 100
order by $order/total descending
return
  &lt;receipt&gt;
    &lt;customer&gt;{ $cust/name/text() }&lt;/customer&gt;
    &lt;total&gt;{ $order/total/text() }&lt;/total&gt;
  &lt;/receipt&gt;
</pre>

</body>
</html>
  • for — iterates over a sequence, binding each item in turn to a variable
  • let — assigns the result of an expression to a variable without iterating
  • where — filters bindings using a boolean condition
  • order by — sorts the remaining bindings before output is produced
  • return — constructs the XML (or other) output for each surviving binding
  • XPath — the path syntax XQuery uses to navigate and select nodes
  • Functions — built-in (fn:count, fn:concat, fn:doc) or user-defined with declare function

Writing Functions and Constructing Elements

A Reusable XQuery Function

<!DOCTYPE html>
<html>
<body>

<pre>
declare function local:discounted-price($price as xs:decimal, $percent as xs:decimal) as xs:decimal {
  $price - ($price * $percent div 100)
};

for $product in doc("catalog.xml")/catalog/product
return
  &lt;product&gt;
    &lt;name&gt;{ data($product/name) }&lt;/name&gt;
    &lt;salePrice&gt;{ local:discounted-price($product/price, 15) }&lt;/salePrice&gt;
  &lt;/product&gt;
</pre>

</body>
</html>
ConceptSQLXQuery
Data shapeFlat rows and columnsNested, ordered tree of elements
Selecting dataSELECT column FROM tablefor $x in doc(...)/path return ...
FilteringWHERE clausewhere clause inside a FLWOR expression
SortingORDER BYorder by clause
JoiningJOIN ... ONNested for/let clauses comparing node values
Note: Tip: Wrap element and attribute values with the data() function (or text()) when you only need the string content — comparing or concatenating raw element nodes instead of their values is one of the most common sources of surprising XQuery results.
Note: XQuery shares its expression syntax with XPath 2.0/3.0 and with the XSLT xsl:function mechanism, so skills transfer in both directions: once you're comfortable writing XQuery FLWOR expressions, XPath predicates and XSLT template matches start to look a lot more familiar.

Exercise: XML XQuery

What is XQuery primarily designed to do?