As we have already seen in the first chapter, FLWOR expressions are functionally equivalent to SQL SELECT statements.
FLWOR expressions enable you to do several things including:
The fundamental building block of FLWOR expressions is the clause.
A FLWOR expression can contain up to eight different clauses:
FLWOR is an acronym made up of the first letter of five of these clauses: 'For', 'Let', 'Where', 'Order by' and 'Return'.
A FLWOR expression must always begin with the keyword for or let.
A FLWOR expression must always end with a return clause.
The for and let clauses begin with the keyword for and let respectively. The window clause does not begin with the keyword window, instead it begins with the keyword for (like the for clause).
The next sections will describe the FLWOR clauses and provide examples showing their usage.
The for clause is used to iterate over items in a sequence.
In its most basic form, the for clause begins with the keyword for followed by a variable declaration (e.g. $x). The variable declaration is followed by the keyword in, followed by an expression which evaluates to a sequence of items.
The variable iterates over the sequence and is bound to each item in turn.
example: for clause iterating over nodes in source xml document
for $i in /people/person return $i/name
<name>mary</name> <name>cindy</name> <name>john</name> <name>peter</name>
example: for clause iterating over sequence of integers
for $i in (1 to 5) return $i
1 2 3 4 5
example: multiple for clauses iterating over different sequences
for $x in (1, 2) for $y in ('a', 'b') return concat ($x, $y)
'1a' '1b' '2a' '2b'
example: multiple variable bindings in one for clause
for $x in (1, 2), $y in ('a', 'b') return concat ($x, $y)
'1a' '1b' '2a' '2b'
The let clause is used to bind further values to variables which will be used later in the FLWOR expression.
The keyword let is followed by the variable name e.g. $a, followed by := and the value which is to be bound to the variable.
example: let clause binding variable to node in source xml document
for $i in /people/person let $a := $i/age return $a
<age>20</age> <age>25</age> <age>40</age> <age>35</age>
example: multiple variable bindings in one let clause
for $i in /people/person let $a := $i/age, $n := $i/name return concat ($n, ' is ', $a)
'mary is 20' 'cindy is 25' 'john is 40' 'peter is 35'
The where clause is used to filter the input stream.
The keyword where is followed by an expression which returns a boolean value. Only those tuples for which the boolean expression returns true are filtered.
Tuples are explained after the next example.
example: where clause filtering nodes from source xml document
for $i in /people/person let $a := $i/age, $n := $i/name where $a < 30 return $n
<name>mary</name> <name>cindy</name>
Tuples are best understood by example:
for $i in /people/person
let $a := $i/age, $n := $i/name
let $a := $i/age, $n := $i/name where $a < 30
let $a := $i/age, $n := $i/name where $a < 30 return $n
The order by clause is used for value based ordering.
The keywords order by are followed by the item (key) used to order the tuple stream.
The qualifiers ascending or descending can be used to indicate the sort order.
example: order by clause sorting filtered sequence in ascending order
for $i in /people/person let $a := $i/age, $n := $i/name where $a < 30 order by $n ascending return $n
<name>cindy</name> <name>mary</name>
The count clause is used to declare a new variable which is bound to the ordinal position of the respective tuple in the tuple stream providing a mechanism to enumerate the tuples.
The keyword count is followed by a variable declaration e.g. $x, which is bound to each tuple in turn.
example: count clause binding variable to each item of input sequence
for $i in /people/person let $n := $i/name count $x return concat ($x, '. ', $n)
'1. mary' '2. cindy' '3. john' '4. peter'
example: count clause binding variable to each item of filtered input sequence
for $i in /people/person let $a := $i/age, $n := $i/name where $a < 30 count $x return concat ($x, '. ', $n)
'1. mary' '2. cindy'
The group by clause is used to group tuples from the input stream which share the same grouping key value.
The keywords group by are followed by an expression representing the grouping key.
example: group by clause grouping input sequence by department
<departments> { for $i in /people/person let $n := <employee>{data($i/name)}</employee>, $d := $i/@dept group by $d return <department name="{$d}"> { $n } </department> } </departments>
<departments> <department name="accounting"> <employee>peter</employee> </department> <department name="marketing"> <employee>cindy</employee> </department> <department name="sales"> <employee>mary</employee> <employee>john</employee> </department> </departments>
The window clause is similar to the for clause in that it too iterates over a binding sequence.
The window clause derives zero or more windows from the binding sequence.
Each window is a sequence of consecutive items from the binding sequence.
The number of windows and the items occuring in each window are determined by the type of window as well as specific constraints.
Constraints are specified in the start and end sections of the window clause.
Constraints use window variables and conditional logic to determine where each window generated from the binding sequence begins and ends.
Much like a for clause, the first line of a window clause begins with the keyword for.
for is followed by a declaration of which type of window(s) will be generated from the binding sequence. There are two types of window: tumbling windows or sliding windows.
The type of window is followed by a user defined variable e.g. $w representing the window itself.
The user defined variable representing the window is followed by the keyword in and the binding sequence from which the window(s) will be derived.
for tumbling window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC')
The start constraint is the second line of the window clause.
As its name implies, the start constraint defines where a window can start.
The start constraint begins with the keyword start followed by window variables e.g $s. The window variables are then followed by the keyword when.
The keyword when is followed by a boolean expression. If the expression returns true the particular item in the binding sequence currently being processed is a candidate for the start of a window (subject to the type of window: tumbling or sliding specified in the first line).
for tumbling window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC') start $s when string-length($s) = 1
In the example above a window can only start with the item being processed if that item is one character long.
The end constraint is optional, if it is specified it appears after the start constraint.
As its name implies, the end constraint defines where a window can end.
The end constraint begins with the keyword end followed by window variables e.g $e. The window variables are then followed by the keyword when.
The keyword when is followed by a boolean expression. If the expression returns true the particular item in the binding sequence currently being processed is a candidate for the end of a window (subject to the type of window: tumbling or sliding specified in the first line).
for tumbling window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC') start $s when string-length($s) = 1 end $e when string-length($e) = 2
In the example above a window can only end with the item being processed if that item is two characters long.
The return clause of a window clause returns the windows generated from the binding sequence.
for tumbling window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC') start $s when string-length($s) = 1 end $e when string-length($e) = 2 return <window> { for $i in $w return <item>{$i}</item> } </window>
In the example above the return statement creates a literal window element for each generated window.
Within the literal window element's opening and closing tags is a for clause which iterates through each item in the current window being processed.
The result of the window clause in this example is two windows.
The first window contains three items 'A' , 'B', and 'BB'.
The second window contains two items 'C' and 'CC'.
<window> <item>A</item> <item>B</item> <item>BB</item> </window> <window> <item>C</item> <item>CC</item> </window>
There are two types of window:
Tumbling windows are windows which never overlap one another. This means that the start item of a new window can only be an item in the binding sequence which occurs after the last item in a previous window (if a previous window exists).
The image below shows two tumbling windows. The first window contains the first three items in the sequence i.e A, B and C . The second window contains two items D and E.
In this particular example the second window starts with the fourth item in the binding sequence, which is the item occuring immediately after the last item in the first window.
Sliding windows are windows which can overlap one another. This means that the start item of a new window can be an item in the binding sequence which is the last item or occurs before the last item of the previous window (if a previous window exists).
The image below shows two sliding windows. The first window contains the first three items in the binding sequence i.e A, B and C . The second window contains three items C, D and E.
In this particular example the second window starts with the third item in the binding sequence i.e. C, which is also the last item in the first window. The windows therefore overlap.
The two examples below demonstrate the difference between tumbling and sliding windows. The window clause in each example is indentical except for the type of window being generated:
example: tumbling window
for tumbling window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC') start $s when string-length($s) = 1 end $e when string-length($e) = 2 return <window> { for $i in $w return <item>{$i}</item> } </window>
<window> <item>A</item> <item>B</item> <item>BB</item> </window> <window> <item>C</item> <item>CC</item> </window>
example: sliding window
for sliding window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC') start $s when string-length($s) = 1 end $e when string-length($e) = 2 return <window> { for $i in $w return <item>{$i}</item> } </window>
<window> <item>A</item> <item>B</item> <item>BB</item> </window> <window> <item>B</item> <item>BB</item> </window> <window> <item>C</item> <item>CC</item> </window>
There are a total of nine different window variables.
In conjunction with the type of window, constraints which make use of window variables determine how many windows will be generated from the binding sequence and which items from the binding sequence will be in each window.
A window can be represented by at least one and at most nine of these variables.
Only one variable is actually mandatory, that being the variable which represents the window itself (the variable declared after the "window type" in the first line of the window clause).
Each variable fulfils a specific role. We have already encountered three of these variables representing the window itself, the start-item and end-item roles.
The nine roles associated with the variables in a window clause are:
The following examples will demonstrate use of several of these roles as well as use of the keyword only.
example: tumbling window demonstrating start-item role
<windows> { for tumbling window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC') start $s when string-length($s) = 1 return <window> { for $i in $w return <item>{$i}</item> } </window> } </windows>
<windows> <window> <item>A</item> </window> <window> <item>B</item> <item>BB</item> <item>BBB</item> </window> <window> <item>C</item> <item>CC</item> <item>CCC</item> <item>CCCC</item> </window> </windows>
example: tumbling window demonstrating start-item and end-item roles
<windows> { for tumbling window $w in ('A', 'B', 'BB', 'BBB', 'C', 'CC', 'CCC', 'CCCC') start $s when string-length($s) = 1 end $e when string-length($e) = 2 return <window> { for $i in $w return <item>{$i}</item> } </window> } </windows>
<windows> <window> <item>A</item> <item>B</item> <item>BB</item> </window> <window> <item>C</item> <item>CC</item> </window> </windows>
example: tumbling window demonstrating start-item-position and end-item-position roles
<windows> { for tumbling window $w in ('A', 'B', 'C', 'D', 'E', 'F', 'G') start at $s when true() end at $e when $e - $s eq 2 return <window> { for $i in $w return <item>{$i}</item> } </window> } </windows>
<windows> <window> <item>A</item> <item>B</item> <item>C</item> </window> <window> <item>D</item> <item>E</item> <item>F</item> </window> <window> <item>G</item> </window> </windows>
example: tumbling window demonstrating start-item-position and end-item-position roles, and 'only' keyword
<windows> { for tumbling window $w in ('A', 'B', 'C', 'D', 'E', 'F', 'G') start at $s when true() only end at $e when $e - $s eq 2 return <window> { for $i in $w return <item>{$i}</item> } </window> } </windows>
<windows> <window> <item>A</item> <item>B</item> <item>C</item> </window> <window> <item>D</item> <item>E</item> <item>F</item> </window> </windows>
example: sliding window demonstrating start-item-position and end-item-position roles and 'only' keyword
<windows> { for sliding window $w in ('A', 'B', 'C', 'D', 'E', 'F', 'G') start at $s when true() end at $e when $e - $s eq 2 return <window> { for $i in $w return <item>{$i}</item> } </window> } </windows>
<windows> <window> <item>A</item> <item>B</item> <item>C</item> </window> <window> <item>B</item> <item>C</item> <item>D</item> </window> <window> <item>C</item> <item>D</item> <item>E</item> </window> <window> <item>D</item> <item>E</item> <item>F</item> </window> <window> <item>E</item> <item>F</item> <item>G</item> </window> <window> <item>F</item> <item>G</item> </window> <window> <item>G</item> </window> </windows>
example: tumbling window demonstrating start-item, end-item and end-next-item roles
<windows> { for tumbling window $w in ( 'A', 'B', 'B', 'A', 'A', 'C', 'D', 'D', 'D', 'E', 'A', 'A') start $s when true() end $e next $e-next when $e-next != $e return <window> { for $i in $w return <item>{$i}</item> } </window> } </windows>
<windows> <window> <item>A</item> </window> <window> <item>B</item> <item>B</item> </window> <window> <item>A</item> <item>A</item> </window> <window> <item>C</item> </window> <window> <item>D</item> <item>D</item> <item>D</item> </window> <window> <item>E</item> </window> <window> <item>A</item> <item>A</item> </window> </windows>
example: tumbling window demonstrating start-item, end-item, start-next-item, end-next-item and end-previous-item roles
<windows> { for tumbling window $w in ( 'A', 'B', 'B', 'A', 'A', 'C', 'D', 'D', 'D', 'E', 'A', 'A') start $s next $s-next when $s = $s-next end $e previous $e-previous next $e-next when $e-previous = $e and $e-next != $e return <window> { for $i in $w return <item>{$i}</item> } </window> } </windows>
<windows> <window> <item>B</item> <item>B</item> </window> <window> <item>A</item> <item>A</item> </window> <window> <item>D</item> <item>D</item> <item>D</item> </window> <window> <item>A</item> <item>A</item> </window> </windows>