Using the At Keyword in XQuery FLWOR Loops
This article provides a comprehensive overview of how positional
variables operate within XQuery FLWOR expressions using the
at keyword. It covers the fundamental syntax, 1-based
indexing mechanism, scoping rules, and practical examples of tracking
item positions when querying XML collections and node sequences.
Understanding the
at Keyword Syntax
In XQuery, a FLWOR (For, Let, Where, Order by, Return) expression
processes sequences of nodes or atomic values. The for
clause iterates over each item in a sequence. By appending the
at keyword followed by a variable name, you bind a
secondary variable that automatically captures the 1-based index of the
current item being processed.
The basic syntax is structured as follows:
for $item at $position in $sequence
return ...
$item: Binds to the current node or value in the sequence.$position: Binds to anxs:integerrepresenting the ordinal position of$itemwithin$sequence.
Key Operational Rules of Positional Variables
- 1-Based Indexing: Unlike many programming languages
that use zero-based indexing, XQuery positional variables are 1-based.
The first item in the sequence assigns
$position = 1, the second$position = 2, and so on. - Scope: The positional variable is scoped to the
specific
foriteration and is accessible throughout the subsequentwhere,order by, andreturnclauses of that iteration. - Evaluation Timing with Filtering: The positional
variable reflects the position of the item in the input sequence
before any
wherefiltering is applied. If awhereclause evaluates to false, that position number is simply omitted from the final output; it does not reset or re-index remaining items. - Multiple
forClauses: When nesting multipleforclauses, each can declare its own independent positional variable. The inner positional variable resets to1for each iteration of the outer loop.
Practical XML Example
Consider the following XML document (catalog.xml):
<catalog>
<product category="hardware">Screwdriver</product>
<product category="software">Editor</product>
<product category="hardware">Hammer</product>
</catalog>Example 1: Basic Enumeration
To assign a numbered rank to every product in the document:
for $prod at $i in doc("catalog.xml")/catalog/product
return
<item index="{$i}">{$prod/text()}</item>
Output:
<item index="1">Screwdriver</item>
<item index="2">Editor</item>
<item index="3">Hammer</item>Example 2: Using the Positional Variable in Predicates and Conditions
Positional variables can be used directly inside where
or return conditional branches:
for $prod at $i in doc("catalog.xml")/catalog/product
where $i mod 2 = 1
return
<odd-item position="{$i}">{$prod/text()}</odd-item>
Output:
<odd-item position="1">Screwdriver</odd-item>
<odd-item position="3">Hammer</odd-item>Summary of Best Practices
- Use
atwhen you need to generate sequence numbers, attribute IDs, alternating row styles (e.g., via$i mod 2), or when chunking and paging data. - If you only need to retrieve elements by position without keeping
track of the iteration index, standard XPath positional predicates
(e.g.,
//product[1]) are often more concise. - To re-index a sequence after filtering, apply the
wherecondition within a sub-expression or pipeline before iterating with thefor ... atloop.