FLWOR

At the heart of XQuery are FLWOR expressions: for-let-where-order by-return. A for clause iterates over a sequence, a let clause binds a variable to a value, a where clause filters, an order by clause sorts, and a return clause builds the result. XQuery 3.0 added an optional group by clause and an optional count clause.

The examples below query the following document:

ch05-flwor-data.xml:
<?xml version="1.0" encoding="UTF-8"?>
<richestMen>
   <billionaire id="1">
      <name>Carlos Slim Helu</name>
      <age>74</age>
      <country>Mexico</country>
      <net_worth>86.1</net_worth>
   </billionaire>
   <billionaire id="2">
      <name>Bill Gates</name>
      <age>58</age>
      <country>USA</country>
      <net_worth>81.2</net_worth>
   </billionaire>
   <billionaire id="3">
      <name>Warren Buffett</name>
      <age>84</age>
      <country>USA</country>
      <net_worth>67.6</net_worth>
   </billionaire>
   <billionaire id="4">
      <name>Amancio Ortega</name>
      <age>78</age>
      <country>Spain</country>
      <net_worth>64.2</net_worth>
   </billionaire>
   <billionaire id="5">
      <name>Larry Ellison</name>
      <age>70</age>
      <country>USA</country>
      <net_worth>51.1</net_worth>
   </billionaire>
</richestMen>

Basic FLWOR: where, let, order by

Filters billionaires with a net worth above 70 (in billion USD), binds each one's id attribute to $id, and orders the result by name.

for $man in richestMen/billionaire
where $man/net_worth > 70
let $id := $man/@id
order by $man/name/text()
return '&#10;Rank ' || $id || ') ' || ($man/name)

Rank 2) Bill Gates Rank 1) Carlos Slim Helu

group by

Groups billionaires by country and, for each group, builds a document element counting its members.

for $man in doc('richestMen.xml')/richestMen/billionaire
let $c := $man/country/text()
group by $c
return document {element {$c} {count($man)}}

113

count clause with stable order by

The count clause binds the current position (before sorting) to $num. stable order by guarantees that ties keep their relative input order; empty least places empty sequences last.

for $age in richestMen/billionaire/age
count $num
stable order by $age descending, $num ascending empty least
return <man num="{$num}">{$age}</man>

84 78 74 70 58

Constructing an HTML table

The at clause of a for binds the current iteration position ($i) alongside the item ($man), useful for numbering rows while building markup with node constructors.

<table>
   {for $man at $i in richestMen/billionaire
   return (<tr><td>{$i}.{$man/name/text()}</td>
                     <td>{$man/net_worth/text()}</td></tr>,
              '&#10;') }
</table>

1.Carlos Slim Helu86.1
2.Bill Gates81.2
3.Warren Buffett67.6
4.Amancio Ortega64.2
5.Larry Ellison51.1