|  | Home · All Classes · Main Classes · Grouped Classes · Modules · Functions |

# A Short Path to XQuery

- Introduction
- Atomic Values

- Using Atomic Values

- More Node Constructors
- Further Reading
- FAQ

- Path expressions misses
- Variable in for loop is out of scope
- Expressions aren't evaluated
- Filters selects the wrong things.
- for/let/order by doesn't behave as expected

### Introduction

While languages such as Java and C++ are largely made of statements, XQuery has expressions at its core. There is a plethora of expressions available ranging from sorting to function calls, but one of the simplest are direct node constructors, like this one:

     <myElement/>

This is an XQuery query, and it also happens to be a well-formed XML document. All the usual types of nodes that can be found in an XML document can be used as expressions in XQuery, and one can go ahead and embed other expressions inside them, by using curly braces:

     (: Copy the value of xml:id attribute from other.html. This is a comment by the way! :)
     <html xmlns="http://www.w3.org/1999/xhtml/"
           xml:id="{doc("other.html")/html/@xml:id}"/>

### Atomic Values

Apart from nodes, XQuery has atomic values and they are just what one would think they are: small, primitive values. Here's a run down of some of the most common:

Name | Description
--- | ---
`xs:integer` | A 64 bit integer
`xs:boolean` | A boolean value, `false` or `true`
`xs:double` | A 64 bit floating point value
`xs:string` | A string where each codepoint is an XML 1.0 character(essentially Unicode)
`xs:date` | A date, such as when you're born: `1984-10-15`
`xs:time` | A time, such as when you show up at work: `09:00:00`
`xs:dateTime` | A date followed by a time: 1984-10-15T05:00:00
`xs:duration` | A time interval such as P5Y2M10DT15H, which represents five years, two months, 10 days, and 15 hours.
`xs:base64Binary` | Represents data, possibly binary data, in Base 64 encoding.

Integers, doubles and strings can be created by using literal expressions, booleans with the functions `true()` or `false()` (just `true` or `false` would be name tests), and for the rest constructor functions must be used. Here's a query illustrating this, which evaluates to a sequence of mixed atomic values:

     declare variable $date := fn:current-date(); (: This line should not be part of the example. It exists in order to make the query valid. :)
     fn:current-date() - $date > xs:dayTimeDuration("P365D")

Each atomic type can construct a value from a string. While doing so it validates the input string to ensure it has a proper format and if not, it issues a query error. These formats tend to be as one would guess it to be. For instance, if one passes "1.five" to `xs:decimal`'s constructor, as opposed to "1.5" it will halt the query such that the bug can be corrected.

In the example an `xs:boolean` was created from an `xs:integer` as opposed to from a string, and that's because values doesn't have to be constructed from strings, they can be created, or converted, from a range of different types. For instance, an `xs:double` can be created from a `xs:decimal`, or a `xs:boolean` can be converted to an `xs:string`. What conversions that are possible depends on the types but they tend to be intuitive. One of the specifications has a nifty table outlining those.

#### Using Atomic Values

Once atomic values have been constructed, via one of the methods mentioned above, or as return values from functions or by evaluating variables, one can pass them along to functions, convert them to strings and attach them as part of text nodes to nodes, or use operators between them. Let's look at the latter.

Apart from the usual arithmetic operators between numbers one would expect, they are also available between more exotic types. Have a look at this query:

     declare variable $date := fn:current-date(); (: This line should not be part of the example. It exists in order to make the query valid. :)
     fn:current-date() - $date > xs:dayTimeDuration("P365D")

It substracts two dates which returns an `xs:dayTimeDuration`, which it subsequently compares against another `:xs:dayTimeDuration`. The query finally evaluates to a single atomic value of type `xs:boolean`.

The available operators and between what types are summarized in a table in the main XQuery specification.

### More Node Constructors

### Further Reading

XQuery is a big language that is hard to cover in an overview. If one wants a good understanding of the subject, a good thing could be to get a book on topic, in the same manner that one has a book on C++.

Another alternative is to ask a question or two on the mailing lists qt-interest or talk on x-query.com.

Of course, the specifications is one alternative, but one has to take a deep breath before diving into those. Here are the links to (some of) them:

- XQuery 1.0: An XML Query Language is the main specification that describes the syntax and behavior.
- XQuery 1.0 and XPath 2.0 Functions and Operators describes all the builtin functions, and how conversions between atomic values are done.

### FAQ

#### Path expressions misses

Often this is caused by that the names that the axis step matches, is different from nodes being matched. For instance, let's say that `index.html` in this query:

     (: Select all paragraphs that contains examples. :)
     doc("index.html")/html/body/p[@class="example"]

is an XHTML document and hence it resides in the namespace `http://www.w3.org/1999/xhtml/`. The path won't match since they look for `{}html` and so forth, while the actual name is `{http://www.w3.org/1999/xhtml/}html`. The fix is straight forward:

     declare namespace x = "http://www.w3.org/1999/xhtml/";
     (: Select all paragraphs that contains examples. :)
     doc("index.html")/x:html/x:body/x:p[@class="example"]

Path expressions also pick up the default namespace if one is declared:

     declare default element namespace "http://www.w3.org/1999/xhtml/";
     <html>
         <body>
             {
                 for $i in doc("testResult.xml")/tests/test[@status = "failure"]
                 order by $i/@name
                 return <p>{$i/@name}</p>
             }
         </body>
     </html>

In this case the nodes created by the direct element constructors will be in the XHTML namespace, but so will the path expressions. Hence they look for `{http://www.w3.org/1999/xhtml/}tests` and so forth, while `testResult.xml` is perhaps in a different namespace, or no namespace at all.

Another reason is that the context item is not what one expects it to be. For instance, this expression:

     doc("myPlainHTML.html")/body

won't match because the node the `doc()` function returns is not the top element node(`html`), it is the document node.

#### Variable in for loop is out of scope

Due to expression precedence it might be necessary to wrap the `return` expression in a `for` clause with paranteses:

     for $i in(reverse(1 to 10)),
         $d in xs:integer(doc("numbers.xml")/numbers/number)
     return ($i + $d)

Without the paranteses on the last line, the arithmetic expression would have had the whole `for` clause as it left operand, and since the scope of variable `$d` ends at the `return` clause, the variable reference would be out of scope.

#### Expressions aren't evaluated

If an expression is inside a node constructor it must be surrounded by braces, otherwise it's interpreted as text. This:

     <e>sum({(1, 2, 3)})</e>

evaluates to:

     <?xml version="1.0" encoding="UTF-8"?>
     <e>sum(1 2 3)</e>

while:

     <e>sum({(1, 2, 3)})</e>

evaluates to:

     <e>6</e>

#### Filters selects the wrong things.

When having predicates, consider what the predicate applies to. For instance, this query:

     <doc>
         <p>
             <span/>
             <span/>
         </p>
         <p>
             <span/>
             <span/>
         </p>
     </doc>/p/span[1]

evaluates to the first `span` elements in each `p` element, while this query:

     (<doc>
         <p>
             <span/>
             <span/>
         </p>
         <p>
             <span/>
             <span/>
         </p>
     </doc>/p/span)[1]

evaluates to only one `span` element, the one that occured first in the result of the path expression as a whole. In the first case the filter expression was applied for the `span` step.

#### for/let/order by doesn't behave as expected

Note that a `for` expression generates a so called tuple stream, while a `let` clause is an ordinary variable binding. For instance, if a `let` binding is placed inside a `for` binding it is created for each tuple. The `order` `by` clause in turn applies to the result of the tuple stream that the `for` clause evaluates to. Consider:

     for $a in (8, -4, 2)
     let $b := ($a * -1, 2)
     order by $a
     return $b

which evaluates to 4 2 -2 2 -8 2.

This expression:

     let $i := (3, 2, 1)
     order by $i[1]
     return $i

wouldn't be sorted(assuming the expression could be evaluated at all, currently it has a type error since the `order` `by` expression requires at most one item, while three are passed) since the items the `let` clause binds aren't dealt with on an individual basis.