XQuery 3.0 Features

XQuery 3.0 has been released as a working draft in December 2011. The new XQuery 3.0 specification standardizes many of the features which had been available as extension modules in eXist and other implementations for quite a while, for example: higher-order functions or try/catch.

As of February 2012, we implemented a good part of the XQuery 3.0 syntax, including:

The following sections present usage examples for those new features. If you click on the edit link, the example snippet will be loaded into eXide so you can run, edit and play around with it.

Switch statements

xquery version "3.0";

let $animal := "Duck"
return
    switch ($animal)
       case "Cow" return "Moo"
       case "Cat" return "Meow"
       case "Duck" return "Quack"
       case "Dog" case "Pitbull" return "Wuff"
       default return "What's that odd noise?"
        

String concatenation

xquery version "3.0";

let $who := "world"
return
    "Hello " || $who || "!"
        

Try/Catch

Basic example catching any errors:

xquery version "3.0";
    
let $x := "Hello"
return
    try {
        $x cast as xs:integer
    } catch * {
        <error>Caught error {$err:code}: {$err:description}</error>
        }

Generating your own errors:

xquery version "3.0";
    
declare namespace app="http://exist-db.org/myapp";

declare variable $app:ERROR := xs:QName("app:error");

try {
    error($app:ERROR, "Ooops", "any data")
} catch app:error {
    <error>Caught error {$err:code}: {$err:description}. Data: {$err:value}.</error>
}

Higher-order Functions

Passing an inline function as parameter

xquery version "3.0";

declare namespace ex="http://exist-db.org/xquery/ex";

declare function ex:apply($func, $list) {
    for $item in $list return $func($item)
};

(: Create an inline function and assign it to $f2 :)
let $f2 := function($a) { upper-case($a) }
return
       ex:apply($f2, ("Hello", "world!"))
            

Using a named function reference

xquery version "3.0";

declare namespace ex="http://exist-db.org/xquery/ex";

declare function ex:apply($func as function(item()) as item()*, $list) {
    for $item in $list return $func($item)
};

(: Use function reference literal to find function at compile time :)
let $fApply := ex:apply#2
return
       $fApply(function($a) { upper-case($a) }, ("Hello", "world!"))
            

Using a dynamic function lookup

xquery version "3.0";

declare namespace ex="http://exist-db.org/xquery/ex2";

declare function ex:fold-left(
        $f as function(item()*, item()) as item()*, 
        $zero as item()*, 
        $seq as item()*) as item()* {
    if (fn:empty($seq)) then $zero
    else ex:fold-left($f, $f($zero, $seq[1]), subsequence($seq, 2))
};

(: Function reference is resolved dynamically at runtime :)
let $foldLeft := function-lookup(xs:QName("ex:fold-left"), 3)
return
    $foldLeft(function($a, $b) { $a * $b}, 1, 1 to 5)
            

Basic higher-order functions

The default function library provides a number of basic functions which take function items as arguments:

fn:map

map(function($a) { $a * $a }, 1 to 5)
            

fn:filter

fn:filter(function($a) {$a mod 2 = 0}, 1 to 10)

Closures

Inline function using variable from local context

xquery version "3.0";

declare function local:apply($names as xs:string*, $f as function(xs:string) as xs:string) {
    for $name in $names
    return
        $f($name)
};

let $string := "Hello "
let $f := function($name as xs:string) {
    (: $string will be copied into the functions context :)
    $string || $name
}
return
    local:apply(("Hans", "Rudi"), $f)
            

Partial function application

When passing functions as arguments, it is often useful to be able to set certain fixed parameters when creating the function reference. XQuery 3.0 allows this using ? as an argument placeholder.

Multiply each item in a sequence with a base value

xquery version "3.0";
            
declare namespace ex="http://exist-db.org/xquery/ex";

declare function ex:multiply($base, $number) {
    $base * $number
};

let $fMultiply := ex:multiply(10, ?)
return
    map($fMultiply, 1 to 10)