XQuery FLWOR

FLWOR is the heart of XQuery. It stands for For, Let, Where, Order by, Return — five clauses that combine to form a complete query expression. FLWOR is to XQuery what SELECT-FROM-WHERE-ORDER BY is to SQL. Once you understand FLWOR, you can write complex XQuery queries that filter, sort, group, and reshape XML data.

FLWOR Structure

for $variable in expression     ← iterate over a sequence
let $variable := expression     ← bind a value to a variable
where condition                 ← filter results
order by expression             ← sort results
return expression               ← define the output for each iteration

Only for and return are required. The others are optional.

Working XML File: employees.xml

<company>
  <employee dept="Engineering">
    <name>Arjun Kumar</name><salary>85000</salary><experience>5</experience>
  </employee>
  <employee dept="Design">
    <name>Meena Pillai</name><salary>72000</salary><experience>3</experience>
  </employee>
  <employee dept="Engineering">
    <name>Ravi Sharma</name><salary>91000</salary><experience>8</experience>
  </employee>
  <employee dept="HR">
    <name>Sunita Joshi</name><salary>58000</salary><experience>2</experience>
  </employee>
</company>

The for Clause

The for clause binds each node in a sequence to a variable, one at a time. The dollar sign $ marks a variable in XQuery.

for $emp in doc("employees.xml")/company/employee
return $emp/name

Output

<name>Arjun Kumar</name>
<name>Meena Pillai</name>
<name>Ravi Sharma</name>
<name>Sunita Joshi</name>

The where Clause — Filtering

The where clause filters iterations — only those where the condition is true produce output.

for $emp in doc("employees.xml")/company/employee
where $emp/salary > 75000
return $emp/name

Output — only high earners

<name>Arjun Kumar</name>
<name>Ravi Sharma</name>

The order by Clause — Sorting

The order by clause sorts results before returning them. Add descending for reverse order; default is ascending.

for $emp in doc("employees.xml")/company/employee
order by $emp/salary descending
return
  <result>
    <name>{ $emp/name/text() }</name>
    <salary>{ $emp/salary/text() }</salary>
  </result>

Output — sorted highest salary first

<result><name>Ravi Sharma</name><salary>91000</salary></result>
<result><name>Arjun Kumar</name><salary>85000</salary></result>
<result><name>Meena Pillai</name><salary>72000</salary></result>
<result><name>Sunita Joshi</name><salary>58000</salary></result>

The let Clause — Variables

The let clause assigns a value or sequence to a variable for use later in the query. Unlike for, let does not create a loop — it binds the whole sequence at once.

let $allEmployees := doc("employees.xml")/company/employee
let $avgSalary := avg($allEmployees/salary)
return
  <summary>
    <totalEmployees>{ count($allEmployees) }</totalEmployees>
    <averageSalary>{ $avgSalary }</averageSalary>
  </summary>

Output

<summary>
  <totalEmployees>4</totalEmployees>
  <averageSalary>76500</averageSalary>
</summary>

Complete FLWOR with All Clauses

A query that finds Engineering employees, calculates a bonus, and returns sorted results:

let $bonus-rate := 0.15
for $emp in doc("employees.xml")/company/employee
where $emp/@dept = "Engineering"
order by $emp/salary descending
return
  <engineerReport>
    <name>{ $emp/name/text() }</name>
    <salary>{ $emp/salary/text() }</salary>
    <bonus>{ $emp/salary * $bonus-rate }</bonus>
    <years>{ $emp/experience/text() }</years>
  </engineerReport>

Output

<engineerReport>
  <name>Ravi Sharma</name>
  <salary>91000</salary>
  <bonus>13650</bonus>
  <years>8</years>
</engineerReport>
<engineerReport>
  <name>Arjun Kumar</name>
  <salary>85000</salary>
  <bonus>12750</bonus>
  <years>5</years>
</engineerReport>

FLWOR vs SQL Comparison

FLWOR ClauseSQL EquivalentPurpose
forFROMIdentifies the data source (iterates nodes)
let(no direct equivalent)Binds variables for reuse
whereWHEREFilters results by condition
order byORDER BYSorts the output
returnSELECTDefines what the output looks like

Nested FLWOR Expressions

FLWOR expressions can nest inside each other to handle hierarchical data.

for $dept in distinct-values(doc("employees.xml")/company/employee/@dept)
return
  <department name="{ $dept }">
  {
    for $emp in doc("employees.xml")/company/employee[@dept = $dept]
    order by $emp/name
    return <member>{ $emp/name/text() }</member>
  }
  </department>

Output

<department name="Design">
  <member>Meena Pillai</member>
</department>
<department name="Engineering">
  <member>Arjun Kumar</member>
  <member>Ravi Sharma</member>
</department>
<department name="HR">
  <member>Sunita Joshi</member>
</department>

Key Points to Remember

  • FLWOR stands for For, Let, Where, Order by, Return.
  • for and return are the only required clauses.
  • for iterates over a sequence; let binds a whole sequence to a variable at once.
  • where filters — only matching iterations produce output.
  • order by sorts the results; add descending for reverse order.
  • return defines the output structure — it can contain XML literals with {} expressions.
  • FLWOR expressions can nest to handle multi-level XML hierarchies.

Leave a Comment

Your email address will not be published. Required fields are marked *