Skip to content
XQuery — FLWOR Expressions, XPath Integration, Full-Text Search, Update Facilities, Use Cases

XQuery — FLWOR Expressions, XPath Integration, Full-Text Search, Update Facilities, Use Cases

DodaTech Updated Jun 20, 2026 7 min read

XQuery is a functional programming language for querying and transforming XML data. Unlike XPath (which selects nodes), XQuery constructs new XML structures. This guide covers FLWOR expressions, XPath integration, full-text search, and practical query patterns.

What You’ll Learn

You’ll write FLWOR expressions (for/let/where/order by/return), integrate XPath for node selection, perform full-text searches, use XQuery Update Facility to modify XML, and apply XQuery to real-world use cases like reporting and data integration.

Learning Path

    flowchart LR
  A[DTD & DOCTYPE] --> B[XQuery<br/>You are here]
  B --> C[XSLT Comparison]
  C --> D[Full-Text Search]
  style B fill:#f90,color:#fff
  

XQuery Overview

XQuery uses XPath expressions to navigate XML and constructs new XML using FLWOR:

(: Basic FLWOR query :)
for $book in doc("books.xml")/bookstore/book
where $book/price > 20
order by $book/title
return
    <expensive-book>
        {$book/title}
        {$book/author}
        <price-with-tax>{$book/price * 1.08}</price-with-tax>
    </expensive-book>

Expected result:

<expensive-book>
    <title>The DOM Guide</title>
    <author>Alice Smith</author>
    <price-with-tax>32.39</price-with-tax>
</expensive-book>
<expensive-book>
    <title>XML for Beginners</title>
    <author>Bob Jones</author>
    <price-with-tax>43.19</price-with-tax>
</expensive-book>

FLWOR Expressions

FLWOR = For, Let, Where, Order by, Return:

for — Iteration

(: Iterate over sequences :)
for $i in (1 to 5)
return <number>{$i}</number>

Output:

<number>1</number>
<number>2</number>
<number>3</number>
<number>4</number>
<number>5</number>

let — Variable Assignment

(: Assign variables for reuse :)
let $doc := doc("books.xml")
let $fiction := $doc//book[@category = "fiction"]
let $count := count($fiction)
return
    <summary>
        <total-books>{count($doc//book)}</total-books>
        <fiction-books>{$count}</fiction-books>
        <fiction-pct>{$count div count($doc//book) * 100}%</fiction-pct>
    </summary>

Output:

<summary>
    <total-books>5</total-books>
    <fiction-books>3</fiction-books>
    <fiction-pct>60%</fiction-pct>
</summary>

where — Filtering

(: Multiple filter conditions :)
for $book in doc("books.xml")//book
where $book/price > 20
  and $book/@category = "fiction"
  and contains($book/title, "XML")
order by $book/price descending
return $book/title

order by — Sorting

(: Sort by multiple criteria :)
for $book in doc("books.xml")//book
order by $book/@category ascending,
         $book/price descending
return
    <entry>
        <category>{data($book/@category)}</category>
        <title>{$book/title/text()}</title>
        <price>{$book/price/text()}</price>
    </entry>

return — Result Construction

(: Conditional construction :)
for $book in doc("books.xml")//book
return
    <book>
        {$book/title}
        {
            if ($book/price > 30) then
                <premium>true</premium>
            else
                <premium>false</premium>
        }
    </book>

XPath Integration

XPath expressions work directly within XQuery:

(: XPath aggregation in XQuery :)
let $books := doc("books.xml")//book
return
    <report>
        <avg-price>{avg($books/price)}</avg-price>
        <max-price>{max($books/price)}</max-price>
        <min-price>{min($books/price)}</min-price>
        <categories>
            {distinct-values($books/@category)}
        </categories>
    </report>

Full-Text Search

XQuery Full Text (XQFT) enables full-text search:

(: Full-text search with scoring :)
for $book in doc("books.xml")//book
where $book/title contains text "XML"
  ftand "Guide" distance at most 3 words
  ftany
order by ft:score($book) descending
return
    <result score="{ft:score($book)}">
        {$book/title}
        <snippet>{$book/title/text()}</snippet>
    </result>

Full-Text Features

(: Case-insensitive search :)
where $book/title contains text "dom" using case insensitive

(: Stemming :)
where $book/description contains text "programming" using stemming
(: Matches: program, programmed, programmer, programming :)

(: Thesaurus expansion :)
where $book/description contains text "car" using thesaurus at "cars.xml"

(: Wildcards :)
where $book/title contains text "XML*" using wildcards

Update Facility

XQuery Update Facility modifies XML documents:

(: Insert a new book :)
insert node
    <book category="reference">
        <title>XQuery Reference</title>
        <author>Carol Davis</author>
        <price>49.99</price>
    </book>
as last into doc("books.xml")/bookstore

(: Update an element :)
replace value of node doc("books.xml")//book[1]/price
with "24.99"

(: Delete an element :)
delete node doc("books.xml")//book[@category = "old"]

(: Rename an element :)
rename node doc("books.xml")//book as "publication"

XQuery Use Cases

Data Integration (from multiple XML sources)

(: Merge data from two XML documents :)
let $customers := doc("customers.xml")//customer
let $orders := doc("orders.xml")//order
return
    <customer-summary>
    {
        for $customer in $customers
        let $customer-orders :=
            $orders[customer-id = $customer/@id]
        return
            <customer id="{$customer/@id}">
                <name>{$customer/name}</name>
                <total-orders>{count($customer-orders)}</total-orders>
                <total-spent>{sum($customer-orders/total)}</total-spent>
            </customer>
    }
    </customer-summary>

Reporting

(: Generate a sales report with grouping :)
let $sales := doc("sales.xml")//sale
let $products := doc("products.xml")//product
return
    <sales-report period="Q2 2026">
    {
        for $product in $products
        let $product-sales :=
            $sales[product-id = $product/@id]
        let $total := sum($product-sales/amount)
        where $total > 0
        order by $total descending
        return
            <product id="{$product/@id}">
                <name>{$product/name}</name>
                <units-sold>{count($product-sales)}</units-sold>
                <revenue>{$total}</revenue>
            </product>
    }
    </sales-report>

Common XQuery Mistakes

1. Confusing for and let

for iterates over each item in a sequence. let assigns the entire sequence to a variable. for $x in (1,2,3) — body runs 3 times. let $x := (1,2,3) — body runs once with variable holding all three.

2. Not Using data() to Get Atomic Values

$book/title returns an element node, not text. Use data($book/title) or $book/title/text() to get the text content. Comparison operators automatically atomize, but construction doesn’t.

3. Inefficient FLWOR Order

Place the most restrictive where clauses first. Filter early to reduce the number of items the order by and return process.

4. Not Using let for Repeated Subexpressions

If you access doc("books.xml")//book[@category="fiction"] multiple times, assign it to a variable with let. This avoids re-parsing the document.

5. Mixing Update and Non-Update Queries

XQuery Update expressions can’t be mixed with non-update queries in the same expression. Use separate queries or XQuery Scripting Extension (XQSE).

6. Ignoring Document Order

XPath/XQuery operates in document order by default. Use unordered {} around expressions where order doesn’t matter for performance gains.

7. String Concatenation Instead of Construction

Avoid concat("<title>", $title, "</title>"). Use direct XML construction: <title>{$title}</title>. It’s cleaner, safer (handles escaping), and faster.

Practice Questions

1. What does FLWOR stand for? For, Let, Where, Order by, Return. For iterates, let assigns variables, where filters, order by sorts, return constructs the result.

2. How does XQuery differ from XSLT? XQuery is a query language (functional, uses FLWOR, returns sequences). XSLT is a transformation language (template-based, rule-driven, transforms one XML to another). XQuery is better for data querying; XSLT for document transformation.

3. What does the data() function do? data() extracts the typed value of a node as an atomic value. For an element, it returns the text content as a string or number. It’s needed when you want values, not nodes.

4. How do you group results in XQuery? Use for to iterate groups, let to gather members:

for $cat in distinct-values($books/@category)
let $group := $books[@category = $cat]
return <category name="{$cat}">{count($group)} books</category>

5. Challenge: Transform a flat XML order list into a customer-centric XML grouped by customer with order totals, sorted by total spend descending. Answer: Use FLWOR: let customers = distinct-values(//customer-id), for each customer let their orders, sum totals, sort descending, construct nested XML with customer info and orders.

Mini Project: XQuery Report Generator

(: sales-report.xq — Generate sales report from XML data :)
xquery version "3.1";

(: Configuration :)
declare variable $data-path := "data/";
declare variable $report-period := "Q2 2026";

(: Load data :)
let $orders := doc($data-path || "orders.xml")//order
let $products := doc($data-path || "products.xml")//product
let $customers := doc($data-path || "customers.xml")//customer

(: Compute metrics :)
let $total-revenue := sum($orders/total)
let $total-orders := count($orders)
let $avg-order-value := $total-revenue div $total-orders
let $unique-customers := count(distinct-values($orders/customer-id))
let $top-products :=
    for $product in $products
    let $product-orders := $orders[product-id = $product/@id]
    let $revenue := sum($product-orders/total)
    order by $revenue descending
    return
        <product rank="{position()}" id="{$product/@id}">
            <name>{$product/name}</name>
            <units-sold>{count($product-orders)}</units-sold>
            <revenue>{$revenue}</revenue>
        </product>

(: Generate report :)
return
    <sales-report generated="{current-date()}">
        <header>
            <period>{$report-period}</period>
            <total-revenue>{$total-revenue}</total-revenue>
            <total-orders>{$total-orders}</total-orders>
            <avg-order-value>{$avg-order-value}</avg-order-value>
            <unique-customers>{$unique-customers}</unique-customers>
        </header>
        <top-products count="10">
            {$top-products[position() <= 10]}
        </top-products>
        <customer-segments>
        {
            let $segments := (
                for $customer in $customers
                let $spend := sum(
                    $orders[customer-id = $customer/@id]/total
                )
                let $segment :=
                    if ($spend > 1000) then "premium"
                    else if ($spend > 500) then "standard"
                    else "basic"
                group by $segment
                return
                    <segment name="{$segment}">
                        <count>{count($customer)}</count>
                        <revenue>{sum($spend)}</revenue>
                    </segment>
            )
            return $segments
        }
        </customer-segments>
    </sales-report>

FAQ

What’s the difference between XPath and XQuery?
XPath selects nodes from XML documents. XQuery queries, transforms, and constructs new XML. XQuery includes XPath as a subset. Think of XPath as SELECT and XQuery as SELECT…INTO.
Can XQuery update XML documents?
Yes — XQuery Update Facility provides insert, delete, replace, rename, and transform operations. It’s an extension (not all processors support it).
What databases support XQuery?
BaseX, eXist-db, MarkLogic, Saxon, and Oracle XML DB. Most relational databases support XQuery through XML extensions (SQL/XML).
Is XQuery faster than XSLT for querying?
Generally yes — XQuery is optimized for data querying and aggregation. XSLT is optimized for document transformation. For extracting and computing with data, XQuery is typically faster.
Can I use XQuery with JSON?
Some processors (like Saxon) support XQuery 3.1 which includes JSON support via json-doc() and json-to-xml() functions.
How do I learn XQuery effectively?
Start with FLWOR expressions on simple XML. Practice by writing queries that solve real problems: reports, data integration, filtering. Use BaseX or Saxon for experimentation.

What’s Next

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-20.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro