FLWOR Expressions

FLWOR expressions (speak: flower) are at the heart of XQuery. In some way, they correspond to the SQL statement SELECT FROM WHERE.

A FLWOR expression contains clauses that are introduced by the keywords for, let, where, order by and return. It begins with at least one of the clauses for and let, may be followed by a where and order by clauses and ends with the return clause. The clauses for and let generate tuples of variable bindings according to the evaluations of the expressions that follow. The where clause restricts and filters the sequence of tuples, the order by clause sorts the results, and the mandatory return clause constructs the result of the FLWOR expression with the help of the expression that follows.

The Clauses for and let

Both for and let clauses use variables that are bound in some way to the evaluations of the expression to follow. The scope of the variable is always its enclosing FLWOR expression. If the same variable has already been bound, the variable name refers to the newly bound variable. If the variable goes out of scope, the variable name refers to the previous binding.

Both clauses bind variables, but they do so quite differently. Consider the following query expression:

let $a := input()/bib/book
return
<p>Currently, there are { count($a) } books stored.</p>

This yields the following result:

<p>Currently, there are 4 books stored.</p>

In a let clause each variable is bound directly to the result of an expression. A single tuple is then generated that contains all variable bindings. The return clause is evaluated once for this single tuple. As $a is bound to all instances of book elements, count($a) evaluates to the total number of books present in the collection. Since the return clause is invoked only once, we get the expected result. Now consider the same expression using the for clause:

for $a in input()/bib/book
return
<p>Currently, there are { count($a) } books stored.</p>

The result is:

<p>Currently, there are 1 books stored.</p>
<p>Currently, there are 1 books stored.</p>
<p>Currently, there are 1 books stored.</p>
<p>Currently, there are 1 books stored.</p>

Instead of creating a single tuple, the for clause creates tuples of variable bindings from the Cartesian product of the sequence of items to which the expressions evaluate. In this example this means that the variable is bound to the evaluation of the expression input()/bib/book resulting in a sequence of four document instances. So $a is bound four times. For each of these bindings a tuple is generated and the return clause is called for each tuple. The count function only sees one document instance at a time.

To further illustrate the processing of for clauses consider this example that is published in a similar form in the W3C XQuery specification:

for $i in (1, 2),
    $j in (3, 4)
return
 <tuple>
   <i>{ $i }</i>
   <j>{ $j }</j>
 </tuple>

In the example before there is only one expression in the for clause so that the Cartesian product is equivalent to the sequence of items that the expression evaluates to. In this query you can see that the tuples of variable bindings are created from the Cartesian product of the sequences (1, 2) and (3, 4):

<tuple><i>1</i><j>3</j></tuple>
<tuple><i>1</i><j>4</j></tuple>
<tuple><i>2</i><j>3</j></tuple>
<tuple><i>2</i><j>4</j></tuple>

If there are for and let clauses in the FLWOR expression then the variable bindings created by the let clause are added to the tuples created by the for clause.

The where Clause

By using the where clause you can define conditions that previously generated tuples must satisfy. If the condition is met, the tuple is retained, if not, the tuple is discarded. It depends on the effective boolean value of the expression in the where clause, whether tuples will be retained or not. For the remaining tuples all variable bindings are still valid so that they can be used in the return clause.

A where clause can simply act as a filter and then represents a more verbose form of a path expression using a predicate. The query expressions

input()/bib/book[@year < 2000]/title

and

for    $a in input()/bib/book
where  $a/@year < 2000
return $a/title

are equivalent: Both return the titles of books that have been published before 2000. They differ in that the path expression additionally performs sorting in document order and elimination of duplicates according to node identity. Therefore it is not necessary to use the FLWOR expression here.

But you can use where clauses for more than defining predicates in path expressions. For example, they are necessary in defining a join criterion:

for    $b in input()/bib/book,
       $a in input()/reviews/entry
where  $b/title = $a/title
return
  <book>
    { $b/author }
    { $b/title }
    { $a/review }
  </book>

See also the section Joining for a short explanation of this example.

The order by and return Clauses

The mandatory return clause determines the result of the whole FLWOR expression. It is invoked for every tuple that is retained after evaluating the where clause. In the expression contained in the where clause you can use any variable bindings of the current FLWOR expression. As you can see from the join example above, this is also the place to use element constructors for tailoring your result.

If there is no order by clause, the order of the tuple stream is determined by the for and let clauses. Otherwise the tuples in the tuple stream are reordered in a new, value-based order. In either case, the resulting order determines the order in which the return clause is evaluated, once for each tuple, using the variable bindings in the respective tuples.

If the values to be compared are strings, you can specify the collation to be used (if no collation is specified, the default collation is used.)