Other Parts of the XQuery FLWOR Expression

We have explored the five clauses of the FLWOR expression that give it its name. But there are a few details we have not touched on, partly because they are not used very often. They are summarized in this section.

Declaring XQuery Types

In the for and let clauses, you can (if you wish) declare the types of each variable. Here are some examples.

for $i as xs:integer in 1 to 5 return $i*2  

for $v as element(video) in //video return $v/runtime  

let $a as element(actor)* := //actor return string($a)  

Declaring types can be useful as a way of asserting what you believe the results of the expressions are, and getting an error message (rather than garbage output) if you have made a mistake. It helps other people coming along later to understand what the code is doing, and to avoid introducing errors when they make changes.

Unlike types declared in other contexts such as function signatures (and unlike variables in XSLT 2.0), the types you declare must be exactly right. The system does not make any attempt to convert the actual value of the expression to the type you declare - for example it will not convert an integer to a double, or extract the string value of an attribute node. If you declare the type as string but the expression delivers an attribute node, that is a fatal error.

XQuery Position Variables

If you have used XSLT and XPath, you have probably come across the position() function, which enables you to number the items in a sequence, or to test whether the current item is the first or the last. FLWOR expressions do not maintain an implicit context in this way. Instead, you can declare an auxiliary variable to hold the current position, like this:

for $v at $pos in //video 
   where $pos mod 2 = 0 
   return $v 

This selects all the even-numbered videos - useful if you are arranging the data in a table. You can use $pos anywhere where you might use the primary variable $v. Its value ranges from 1 to the number of items in the //video sequence. If there are no order by clauses, then the position variables in each for clause follow a nested-loop model as you would expect. If there is an order by clause, the position values represent the position of the items before sorting (which is different from the rule in XSLT).

There are various keywords in the order by clause that give you finer control over how the sorting takes place. The most important is the collation: unfortunately, though, the way collations work is likely to be very product-dependent. The basic idea is that if you are sorting the index at the back of a book, or the names in a phone directory, then you need to apply rather more intelligent rules than simply sorting on the numeric Unicode code value of each character. Upper-case and lower-case variants of letters may need to be treated the same way, and accents on letters have some quite subtle rules in many languages. The working group defining XQuery settled on the simple rule that every collating sequence you might want has a name (specifically, a URI rather like a namespace URI), and it is up to each vendor to decide what collations to provide and how to name them.

Other things you can say in the order specification include defining whether empty values of the sort key (XQuery's equivalent of null values in SQL) should go at the start or end of the sequence, and whether the sort should be stable, in the sense that items with equal sort key values preserve their original order.

Multiple Assignments

One simple syntax note. Instead of writing

for $i in ("a", "b", "c") 
for $j in 1 to 5 
return concat($i, $j) 

you can write:

for $i in ("a", "b", "c"),  
   $j in 1 to 5  
return concat($i, $j) 

The meaning of both is the same. This same technique applies to let statements as well.

Free Stylus Studio XML Training:
W3C Member