XQuery/Sequences
From Wikibooks, the open-content textbooks collection
Contents |
[edit] Motivation
You want to manipulate a sequence of items. These items may be very similar to each other or they may be of very different types.
[edit] Method
We begin with some simple examples of sequences. We then look at the most common sequence operators. XQuery uses the word sequence as a generic name for an ordered container of items.
Understanding how sequences work in XQuery is central to understanding how the language works. The use of generic sequences of items is central to functional programming and stands in sharp contract to other programming languages such as Java or JavaScript that provide multiple methods and functions to handle key-value pairs, dictionaries, arrays and XML data. The wonderful thing about XQuery is that you only need to learn one set of concepts and a very small list of functions to learn how to quickly manipulate data.
[edit] Examples
[edit] Creating sequences of characters and strings
You use the parenthesis to contain a sequence, commas to delimit items and quotes to contain string values:
let $sequence := ('a', 'b', 'c', 'd', 'e', 'f')
Note that you can use single or double quotes, but for most character strings a single quote is used.
let $sequence := ("apple", 'banana', "carrot", 'dog', "egg", 'fig')
You can also intermix data types. For example the following squence has three strings and three integers in the same sequence.
let $sequence := ('a', 'b', 'c', 1, 2, 3)
You can then pass the sequence to any XQuery function that works with sequences of items. For example the count() function takes a sequence as an input and returns the number of items in the sequence.
let $count := count($sequence)
To see the results of these items you can create a simple XQuery that displays the items using a FLOWR statement.
[edit] Viewing items in a sequence
xquery version "1.0";
let $sequence := ('a', 'b', 'c', 'd', 'e', 'f')
let $count := count($sequence)
return
<results>
{for $item in $sequence
return
<item>{$item}</item>
}
<count>{$count}</count>
</results>
<results> <item>a</item> <item>b</item> <item>c</item> <item>d</item> <item>e</item> <item>f</item> </results>
[edit] Adding XML items to your sequence
You can also store XML tags within a sequence.
let $sequence := ('apple', <banana/>, <fruit type="carrot"/>, <animal type='dog'/>, <vehicle>car</vehicle>)
Although you can use parenthesis to create sequence of XML items, the best practice is to use XML tags to begin and end a sequence and to store all items as XML elements. One suggestion is two use items as the element name to hold generic sequences of items.
Here is an example of this:
let $items := <items> <banana/> <fruit type="carrot"/> <animal type='dog'/> <vehicle>car</vehicle> </items>
The other convention is to put all individual items in their own item element tags and to place each item on a separate line of the list of items gets long.
let $items :=
<items>
<item>banana</item>
<item>
<fruit type="carrot"/>
</item>
<item>
<animal type='dog'/>
</item>
<item>
<vehicle>car</vehicle>
</item>
</items>
The following FLOWR expression can then be used to display each of these items:
return
xquery version "1.0";
let $sequence :=
<items>
<item>banana</item>
<item>
<fruit type="carrot"/>
</item>
<item>
<animal type='dog'/>
</item>
<item>
<vehicle>car</vehicle>
</item>
</items>
return
<results>
{for $item in $sequence/item
return
<item>{$item}</item>
}
</results>
This will return the following XML
<results> <item> <item>banana</item> </item> <item> <item> <fruit type="carrot"/> </item> </item> <item> <item> <animal type="dog"/> </item> </item> <item> <item> <vehicle>car</vehicle> </item> </item> </results>
Note that when the resulting XML is returned, only double quotes are present in the output.
[edit] Common Sequence Functions
There are only a handful of functions you will need to use with sequences. We will review these functions and also show you how to create new functions using combinations of these functions.
Here are the three most common non-mathematical functions used with sequences. These three are the real workhorses of XQuery sequences. You can spend days writing XQueries and never need functions beyond these three functions.
count($seq as item()*) - used to count the number of items in a sequence. Returns a non-negative integer.
distinct-values($seq as item()*) - used to remove duplicate items in a sequence. Returns another sequence.
subsequence($seq as item()*, $start as int, $num as int) - used to return only a subset of items in a sequence. Returns another sequence.
All of these functions have a datatype of item()* which is read zero or more items. Note that both the distinct-values() function and the subsequence() function both take in a sequence and return a sequence. This comes in very handy when you are creating recursive functions.
Along with count() are also a few sequence operators that calculate sums and average, min and max:
sum($seq as item()*) - used to sum the values of numbers in a sequence
avg($seq as item()*) - used to calculate the average (arithmetic mean) of numbers in a sequence
min($seq as item()*) - used to find the minimum value of a sequence of numbers
max($seq as item()*) - used to find the maximum value of a sequence of numbers
These functions are designed to work on numeric values of items and all return numeric values. You many want to use the number() function when working with strings of items.
You can go a long way by just learning these three functions. You can also create most other sequence operators from these functions.
[edit] Occasionally Used Sequence Functions
In addition there are some functions that are occasionally used:
insert-before($seq as item()*, $position as int, $inserts as item()*) - for inserting new items anywhere in a sequence
last ($seq as item()*) - returns the last item in a sequence
position() - this function is used to output the position in a FLOWR statement
remove($seq as item()*, $position as int) - removes an items from a sequence
reverse($seq as item()*) - reverses the order of items in a sequence
index-of($seq as anyAtomicType()*, $targetanyAtomicType()) - returns a sequence of integers that
indicate where an item is within a sequence
[edit] Example of Sum Function
Lets imagine that we have a basket of items and we want to count the total items in the basket.
let $basket := <basket> <item> <department>produce</department> <type>apples</type> <count>2</count> </item> <item> <department>produce</department> <type>banana</type> <count>3</count> </item> <item> <department>produce</department> <type>pears</type> <count>5</count> </item> <item> <department>hardware</department> <type>nuts</type> <count>7</count> </item> <item> <department>packaged-goods</department> <type>nuts</type> <count>2</count> </item> </basket>
To sum the counts of each item we will need to use an XPath expression to get only the counts and create a new sequence of just the count values.
Here is that expression:
let $sequence-of-counts := $basket/item/count/text()
This sequence can be returned by the following expression:
for $item in $sequence-of-counts
return <sequence-of-counts> {$item} </sequence-of-counts>
We can then wrap the $sequence-of-counts sequence in the sum function.
let $total := sum($sequence-of-counts)
which can be returned by the following expression:
return <total> {$total} </total>