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.
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.
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.
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.)