Difference between revisions of "XQuery 3.0"

From BaseX Documentation
Jump to navigation Jump to search
m (Text replacement - "syntaxhighlight" to "pre")
 
(36 intermediate revisions by 3 users not shown)
Line 1: Line 1:
This article is part of the [[XQuery|XQuery Portal]].
+
This article is part of the [[XQuery|XQuery Portal]]. It provides a summary of the most important features of the [https://www.w3.org/TR/xquery-30/ XQuery 3.0] Recommendation.
It summarizes the most interesting features of the
 
[http://www.w3.org/TR/xquery-30/ XQuery 3.0] Recommendations.
 
XQuery 3.0 is fully supported by BaseX.
 
  
 
=Enhanced FLWOR Expressions=
 
=Enhanced FLWOR Expressions=
  
Most clauses of FLWOR expressions can now be specified in an arbitrary order: additional {{Code|let}} and {{Code|for}} clauses can be put after a {{Code|where}} clause, and multiple {{Code|where}}, {{Code|order by}} and {{Code|group by}} statements can be used. This means that many nested loops can now be rewritten to a single FLWOR expression.
+
Most clauses of FLWOR expressions can be specified in an arbitrary order: additional {{Code|let}} and {{Code|for}} clauses can be put after a {{Code|where}} clause, and multiple {{Code|where}}, {{Code|order by}} and {{Code|group by}} statements can be used. This means that many nested loops can now be rewritten to a single FLWOR expression.
  
 
'''Example:'''  
 
'''Example:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
for $country in db:open('factbook')//country
+
for $country in db:get('factbook')//country
 
where $country/@population > 100000000
 
where $country/@population > 100000000
let $name := $country/name[1]
 
 
for $city in $country//city[population > 1000000]
 
for $city in $country//city[population > 1000000]
group by $name
+
group by $name := $country/name[1]
return &lt;country name='{ $name }'&gt;{ $city/name }&lt;/country&gt;
+
count $id
 +
return <country id='{ $id }' name='{ $name }'>{ $city/name }</country>
 
</pre>
 
</pre>
  
 
==group by==
 
==group by==
  
FLWOR expressions have been extended to include the [http://www.w3.org/TR/xquery-30/#id-group-by group by] clause, which is well-established among relational database systems. <code>group by</code> can be used to apply value-based partitioning to query results:
+
FLWOR expressions have been extended to include the [https://www.w3.org/TR/xquery-30/#id-group-by group by] clause, which is well-established in SQL. <code>group by</code> can be used to apply value-based partitioning to query results:
  
 
'''XQuery:'''  
 
'''XQuery:'''  
<pre class="brush:xquery">  
+
<pre lang='xquery'>
 
for $ppl in doc('xmark')//people/person   
 
for $ppl in doc('xmark')//people/person   
 
let $ic := $ppl/profile/@income
 
let $ic := $ppl/profile/@income
let $income := if($ic < 30000) then
+
let $income :=
                  "challenge"  
+
  if($ic < 30000) then
                else if($ic >= 30000 and $ic < 100000) then  
+
    "challenge"  
                  "standard"  
+
  else if($ic >= 30000 and $ic < 100000) then  
                else if($ic >= 100000) then  
+
    "standard"  
                  "preferred"  
+
  else if($ic >= 100000) then  
                else  
+
    "preferred"  
                  "na"   
+
  else  
 +
    "na"   
 
group by $income
 
group by $income
 
order by $income
 
order by $income
Line 39: Line 37:
 
</pre>  
 
</pre>  
  
This query is a rewrite of [http://www.ins.cwi.nl/projects/xmark/Assets/xmlquery.txt Query #20] contained in the [http://www.ins.cwi.nl/projects/xmark XMark Benchmark Suite] to use <code>group by</code>.
+
This query is a rewrite of [https://www.ins.cwi.nl/projects/xmark/Assets/xmlquery.txt Query #20] contained in the [https://projects.cwi.nl/xmark/ XMark Benchmark Suite] to use <code>group by</code>.
 
The query partitions the customers based on their income.  
 
The query partitions the customers based on their income.  
  
 
'''Result:'''  
 
'''Result:'''  
<pre class="brush:xml">
+
<pre lang="xml">
 
<challenge>4731</challenge>
 
<challenge>4731</challenge>
 
<na>12677</na>
 
<na>12677</na>
Line 50: Line 48:
 
</pre>
 
</pre>
  
In contrast to the relational GROUP BY statement, the XQuery counterpart
+
In contrast to the relational GROUP BY statement, the XQuery counterpart concatenates the values of all non-grouping variables that belong to a specific group. In the context of our example, all nodes in <code>//people/person</code> that belong to the <code>preferred</code> partition are concatenated in <code class="brush:xquery">$ppl</code> after grouping has finished. You can see this effect by changing the return statement to:
concatenates the values of all non-grouping variables that belong to a specific group.
 
In the context of our example, all nodes in <code>//people/person</code> that belong to the <code>preferred</code> partition are concatenated in <code class="brush:xquery">$ppl</code> after grouping has finished.
 
You can see this effect by changing the return statement to:
 
  
<pre class="brush:xquery">  
+
<pre lang='xquery'>  
 
...
 
...
 
return element { $income } { $ppl }
 
return element { $income } { $ppl }
Line 61: Line 56:
  
 
'''Result:'''
 
'''Result:'''
<pre class="brush:xml">
+
<pre lang="xml">
 
<challenge>
 
<challenge>
 
   <person id="person0">
 
   <person id="person0">
Line 74: Line 69:
  
 
'''XQuery:'''  
 
'''XQuery:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
let $data :=
 
let $data :=
 
   <xml>
 
   <xml>
Line 82: Line 77:
 
   </xml>
 
   </xml>
 
for $person in $data/person
 
for $person in $data/person
group by $country := $person/@country/string()
+
group by $country := $person/@country
 
return element persons {
 
return element persons {
 
   attribute country { $country },
 
   attribute country { $country },
   $person/@name ! element name { data() }
+
   for $name in $person/@name
 +
  return element name { data($name) }
 
}
 
}
 
</pre>
 
</pre>
  
 
'''Result:'''
 
'''Result:'''
<pre class="brush:xml">
+
<pre lang="xml">
 
<persons country="USA">
 
<persons country="USA">
 
   <name>John</name>
 
   <name>John</name>
Line 102: Line 98:
 
==count==
 
==count==
  
A new {{Code|count}} clause enhances the FLWOR expression with a variable that enumerates the iterated tuples.
+
The {{Code|count}} clause enhances the FLWOR expression with a variable that enumerates the iterated tuples.
  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
for $n in (1 to 10)[. mod 2 = 1]
 
for $n in (1 to 10)[. mod 2 = 1]
 
count $c
 
count $c
return &lt;number count="{ $c }" number="{ $n }"/&gt;
+
return <number count="{ $c }" number="{ $n }"/>
 
</pre>
 
</pre>
  
Line 114: Line 110:
 
The {{Code|allowing empty}} provides functionality similar to outer joins in SQL:
 
The {{Code|allowing empty}} provides functionality similar to outer joins in SQL:
  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
for $n allowing empty in ()
 
for $n allowing empty in ()
 
return 'empty? ' || empty($n)
 
return 'empty? ' || empty($n)
Line 123: Line 119:
 
Window clauses provide a rich set of variable declarations to process sub-sequences of iterated tuples. An example:
 
Window clauses provide a rich set of variable declarations to process sub-sequences of iterated tuples. An example:
  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14)
 
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14)
     start at $s when fn:true()
+
     start at $s when true()
 
     only end at $e when $e - $s eq 2
 
     only end at $e when $e - $s eq 2
return &lt;window&gt;{ $w }&lt;/window&gt;
+
return <window>{ $w }</window>
 
</pre>
 
</pre>
  
More information on window clauses, and all other enhancements, can be found in the [http://www.w3.org/TR/xquery-30/#id-windows specification].
+
More information on window clauses, and all other enhancements, can be found in the [https://www.w3.org/TR/xquery-30/#id-windows specification].
 +
 
 +
=Function Items=
 +
 
 +
One of the most distinguishing features added in ''XQuery 3.0'' are ''function items'', also known as ''lambdas'' or ''lambda functions''. They make it possible to abstract over functions and thus write more modular code.
 +
 
 +
'''Examples:'''
 +
 
 +
Function items can be obtained in three different ways:
 +
 
 +
<ul>
 +
<li>Declaring a new ''inline function'':
 +
<pre lang='xquery'>let $f := function($x, $y) { $x + $y }
 +
return $f(17, 25)</pre>
 +
'''Result:''' <code>42</code>
 +
</li>
 +
<li>Getting the function item of an existing (built-in or user-defined) XQuery function. The arity (number of arguments) has to be specified as there can be more than one function with the same name:
 +
<pre lang='xquery'>let $f := math:pow#2
 +
return $f(5, 2)</pre>
 +
'''Result:''' <code>25</code>
 +
</li>
 +
<li>''Partially applying'' another function or function item. This is done by supplying only some of the required arguments, writing the placeholder <code>?</code> in the positions of the arguments left out. The produced function item has one argument for every placeholder.
 +
<pre lang='xquery'>let $f := substring(?, 1, 3)
 +
return (
 +
  $f('foo123'),
 +
  $f('bar456')
 +
)</pre>
 +
'''Result:''' <code>foo bar</code>
 +
</li>
 +
</ul>
 +
 
 +
Function items can also be passed as arguments to and returned as results from functions. These so-called [[Higher-Order Functions]] like <code>for-each</code> and <code>fold-left</code> are discussed in more depth on their own Wiki page.
  
 
=Simple Map Operator=
 
=Simple Map Operator=
  
The [http://www.w3.org/TR/xquery-30/#id-map-operator simple map] operator {{Code|!}} provides a compact notation for applying the results of a first to a second expression: the resulting items of the first expression are bound to the context item one by one, and the second expression is evaluated for each item. The map operator may be used as replacement for FLWOR expressions:
+
The [https://www.w3.org/TR/xquery-30/#id-map-operator simple map] operator {{Code|!}} provides a compact notation for applying the results of a first to a second expression: the resulting items of the first expression are bound to the context item one by one, and the second expression is evaluated for each item. The map operator may be used as replacement for FLWOR expressions:
  
 
'''Example:'''  
 
'''Example:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
(: Simple map notation :)
 
(: Simple map notation :)
 
(1 to 10) ! element node { . },
 
(1 to 10) ! element node { . },
Line 145: Line 172:
 
</pre>
 
</pre>
  
A map operator is defined to be part of a path expression, which may now mix path and map operators. In contrast to the path operator, the results of the map operator will not be made duplicate-free and returned in document order.
+
In contrast to path expressions, the results of the map operator will not be made duplicate-free and returned in document order.
  
 
=Try/Catch=
 
=Try/Catch=
  
The [http://www.w3.org/TR/xquery-30/#id-try-catch try/catch] construct can be used to handle errors at runtime:
+
The [https://www.w3.org/TR/xquery-30/#id-try-catch try/catch] construct can be used to handle errors at runtime:
  
 
'''Example:'''  
 
'''Example:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
try {
 
try {
 
   1 + '2'
 
   1 + '2'
Line 171: Line 198:
 
* {{Code|$err:line-number}}: line number where the error occurred
 
* {{Code|$err:line-number}}: line number where the error occurred
 
* {{Code|$err:column-number}}: column number where the error occurred
 
* {{Code|$err:column-number}}: column number where the error occurred
* {{Code|$err:additional}}: error stack trace
 
  
 
=Switch=
 
=Switch=
  
The [http://www.w3.org/TR/xquery-30/#id-switch switch] statement is available in many other programming languages. It chooses one of several expressions to evaluate based on its input value.
+
The [https://www.w3.org/TR/xquery-30/#id-switch switch] statement is available in many other programming languages. It chooses one of several expressions to evaluate based on its input value.
  
 
'''Example:'''  
 
'''Example:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
for $fruit in ("Apple", "Pear", "Peach")
 
for $fruit in ("Apple", "Pear", "Peach")
 
return switch ($fruit)
 
return switch ($fruit)
Line 191: Line 217:
  
 
'''Example:'''
 
'''Example:'''
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
for $fruit in ("Apple", "Cherry")
 
for $fruit in ("Apple", "Cherry")
 
return switch ($fruit)
 
return switch ($fruit)
Line 205: Line 231:
 
</pre>
 
</pre>
 
'''Result:''' <code>red red</code>
 
'''Result:''' <code>red red</code>
 
=Function Items=
 
 
One of the most distinguishing features added in ''XQuery 3.0'' are ''function items'', also known as ''lambdas'' or ''lambda functions''. They make it possible to abstract over functions and thus write more modular code.
 
 
'''Examples:'''
 
 
Function items can be obtained in three different ways:
 
 
<ul>
 
<li>Declaring a new ''inline function'':
 
<pre class="brush:xquery">let $f := function($x, $y) { $x + $y }
 
return $f(17, 25)</pre>
 
'''Result:''' <code>42</code>
 
</li>
 
<li>Getting the function item of an existing (built-in or user-defined) XQuery function. The arity (number of arguments) has to be specified as there can be more than one function with the same name:
 
<pre class="brush:xquery">let $f := math:pow#2
 
return $f(5, 2)</pre>
 
'''Result:''' <code>25</code>
 
</li>
 
<li>''Partially applying'' another function or function item. This is done by supplying only some of the required arguments, writing the placeholder <code>?</code> in the positions of the arguments left out. The produced function item has one argument for every placeholder.
 
<pre class="brush:xquery">let $f := fn:substring(?, 1, 3)
 
return (
 
  $f('foo123'),
 
  $f('bar456')
 
)</pre>
 
'''Result:''' <code>foo bar</code>
 
</li>
 
</ul>
 
 
Function items can also be passed as arguments to and returned as results from functions. These so-called [[Higher-Order Functions]] like <code>fn:map</code> and <code>fn:fold-left</code> are discussed in more depth on their own Wiki page.
 
  
 
=Expanded QNames=
 
=Expanded QNames=
  
A ''QName'' can now be directly prefixed with the letter "Q" and a namespace URI in the [http://www.jclark.com/xml/xmlns.htm Clark Notation].
+
A ''QName'' can be prefixed with the letter {{Code|Q}}, the namespace URI wrapped in curly braces and the local name.
  
 
'''Examples:'''
 
'''Examples:'''
 
* <code><nowiki>Q{http://www.w3.org/2005/xpath-functions/math}pi()</nowiki></code> returns the number π
 
* <code><nowiki>Q{http://www.w3.org/2005/xpath-functions/math}pi()</nowiki></code> returns the number π
 
* <code>Q{java:java.io.FileOutputStream}new("output.txt")</code> creates a new Java file output stream
 
* <code>Q{java:java.io.FileOutputStream}new("output.txt")</code> creates a new Java file output stream
 
The syntax differed in older versions of the XQuery 3.0 specification, in which the prefixed namespace URI was quoted:
 
 
* <code><nowiki>"http://www.w3.org/2005/xpath-functions/math":pi()</nowiki></code>
 
* <code>"java:java.io.FileOutputStream":new("output")</code>
 
  
 
=Namespace Constructors=
 
=Namespace Constructors=
  
New namespaces can now be created via so-called 'Computed Namespace Constructors'.
+
New namespaces can be created via so-called 'Computed Namespace Constructors'.
  
<pre class="brush:xquery">  
+
<pre lang='xquery'>  
 
element node { namespace pref { 'http://url.org/' } }
 
element node { namespace pref { 'http://url.org/' } }
 
</pre>
 
</pre>
Line 260: Line 250:
 
=String Concatenations=
 
=String Concatenations=
  
Two vertical bars <code>||</code> (also named ''pipe characters'') can be used to concatenate strings. This operator is a shortcut for the {{Code|fn:concat()}} function.
+
Two vertical bars <code>||</code> (also named ''pipe characters'') can be used to concatenate strings. This operator is a shortcut for the {{Code|concat()}} function.
  
<pre class="brush:xquery">  
+
<pre lang='xquery'>  
 
'Hello' || ' ' || 'Universe'
 
'Hello' || ' ' || 'Universe'
 
</pre>
 
</pre>
Line 268: Line 258:
 
=External Variables=
 
=External Variables=
  
Default values can now be attached to external variable declarations. This way, an expression can also be evaluated if its external variables have not been bound to a new value.
+
Default values can be attached to external variable declarations. This way, an expression can also be evaluated if its external variables have not been bound to a new value.
  
<pre class="brush:xquery">  
+
<pre lang='xquery'>  
 
declare variable $user external := "admin";
 
declare variable $user external := "admin";
 
"User:", $user
 
"User:", $user
Line 277: Line 267:
 
=Serialization=
 
=Serialization=
  
[[Serialization|Serialization ]]parameters can now be defined within XQuery expressions. Parameters are placed in the query prolog and need to be specified as option declarations, using the <code>output</code> prefix.
+
[[Serialization]] parameters can be defined within XQuery expressions. Parameters are placed in the query prolog and need to be specified as option declarations, using the <code>output</code> prefix.
  
 
'''Example:'''  
 
'''Example:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
 
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
 
declare option output:omit-xml-declaration "no";
 
declare option output:omit-xml-declaration "no";
 
declare option output:method "xhtml";
 
declare option output:method "xhtml";
&lt;html/&gt;
+
<html/>
 
</pre>  
 
</pre>  
 
'''Result:''' <code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;html&gt;&lt;/html&gt;</code>
 
'''Result:''' <code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;html&gt;&lt;/html&gt;</code>
Line 292: Line 282:
 
=Context Item=
 
=Context Item=
  
The context item can now be specified in the prolog of an XQuery expression:
+
The context item can be specified in the prolog of an XQuery expression:
  
 
'''Example:'''  
 
'''Example:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
declare context item := document {
 
declare context item := document {
 
   <xml>
 
   <xml>
Line 313: Line 303:
  
 
'''Example:'''  
 
'''Example:'''  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
declare %private function local:max($x1, $x2) {
 
declare %private function local:max($x1, $x2) {
 
   if($x1 > $x2) then $x1 else $x2
 
   if($x1 > $x2) then $x1 else $x2
Line 320: Line 310:
 
local:max(2, 3)
 
local:max(2, 3)
 
</pre>
 
</pre>
 
The following implementation-defined annotations are available:
 
 
* {{Code|%basex:inline([limit])}} enforces the inlining of a function. Example:
 
 
'''Example:'''
 
<pre class="brush:xquery">
 
declare option db:inlinelimit '0';
 
declare %basex:inline function local:id($x) { $x };
 
local:id(123)
 
</pre>
 
 
In this query, function inlining has been deactivated by setting [[Options#INLINELIMIT|inlinelimit]] to {{Code|0}}. The annotation enforces inlining for the given function, though, resulting in the optimized query expression {{Code|123}}.
 
 
If an integer is specified as annotation argument, it will be interpreted a local inline limit.
 
 
* {{Code|%basex:lazy}} enforces the lazy evaluation of a global variable. Example:
 
 
'''Example:'''
 
<pre class="brush:xquery">
 
declare %basex:lazy variable $january := doc('does-not-exist');
 
if(month-from-date(current-date()) == 1) then $january else ()
 
</pre>
 
 
The annotation ensures that an error will only be thrown if the condition yields true. Without the annotation, the error will always be thrown, because the referenced document is not found.
 
  
 
=Functions=
 
=Functions=
  
The following functions have been added in the [http://www.w3.org/TR/xpath-functions-30/ XQuery 3.0 Functions and Operators] Specification:
+
The following functions have been added in the [https://www.w3.org/TR/xpath-functions-31/ XQuery 3.0 Functions and Operators] Specification:
  
<code>fn:analyze-string</code>* <code>fn:available-environment-variables</code>, <code>fn:element-with-id</code>, <code>fn:environment-variable</code>, <code>fn:filter</code>, <code>fn:fold-left</code>, <code>fn:fold-right</code>, <code>fn:format-date</code>, <code>fn:format-dateTime</code>, <code>fn:format-integer</code>, <code>fn:format-number</code>, <code>fn:format-time</code>, <code>fn:function-arity</code>, <code>fn:function-lookup</code>, <code>fn:function-name</code>, <code>fn:generate-id</code>, <code>fn:has-children</code>, <code>fn:head</code>, <code>fn:innermost</code>, <code>fn:map</code>, <code>fn:map-pairs</code>, <code>fn:outermost</code>, <code>fn:parse-xml</code>, <code>fn:parse-xml-fragment</code>, <code>fn:path</code>, <code>fn:serialize</code>, <code>fn:tail</code>, <code>fn:unparsed-text</code>, <code>fn:unparsed-text-available</code>, <code>fn:unparsed-text-lines</code>, <code>fn:uri-collection</code>
+
<code>analyze-string</code>, <code>available-environment-variables</code>, <code>element-with-id</code>, <code>environment-variable</code>, <code>filter</code>, <code>fold-left</code>, <code>fold-right</code>, <code>for-each</code>, <code>for-each-pair</code>, <code>format-date</code>, <code>format-dateTime</code>, <code>format-integer</code>, <code>format-number</code>, <code>format-time</code>, <code>function-arity</code>, <code>function-lookup</code>, <code>function-name</code>, <code>generate-id</code>, <code>has-children</code>, <code>head</code>, <code>innermost</code>, <code>outermost</code>, <code>parse-xml</code>, <code>parse-xml-fragment</code>, <code>path</code>, <code>serialize</code>, <code>tail</code>, <code>unparsed-text</code>, <code>unparsed-text-available</code>, <code>unparsed-text-lines</code>, <code>uri-collection</code>
  
 
New signatures have been added for the following functions:
 
New signatures have been added for the following functions:
  
<code>fn:document-uri</code>, <code>fn:string-join</code>, <code>fn:node-name</code>, <code>fn:round</code>, <code>fn:data</code>
+
<code>document-uri</code>, <code>string-join</code>, <code>node-name</code>, <code>round</code>, <code>data</code>
  
 
=Changelog=
 
=Changelog=
 
;Version 8.0
 
 
* Added: %basex:inline, %basex:lazy
 
  
 
;Version 7.7
 
;Version 7.7

Latest revision as of 18:38, 1 December 2023

This article is part of the XQuery Portal. It provides a summary of the most important features of the XQuery 3.0 Recommendation.

Enhanced FLWOR Expressions[edit]

Most clauses of FLWOR expressions can be specified in an arbitrary order: additional let and for clauses can be put after a where clause, and multiple where, order by and group by statements can be used. This means that many nested loops can now be rewritten to a single FLWOR expression.

Example:

for $country in db:get('factbook')//country
where $country/@population > 100000000
for $city in $country//city[population > 1000000]
group by $name := $country/name[1]
count $id
return <country id='{ $id }' name='{ $name }'>{ $city/name }</country>

group by[edit]

FLWOR expressions have been extended to include the group by clause, which is well-established in SQL. group by can be used to apply value-based partitioning to query results:

XQuery:

for $ppl in doc('xmark')//people/person  
let $ic := $ppl/profile/@income
let $income :=
  if($ic < 30000) then
    "challenge" 
  else if($ic >= 30000 and $ic < 100000) then 
    "standard" 
  else if($ic >= 100000) then 
    "preferred" 
  else 
    "na"  
group by $income
order by $income
return element { $income } { count($ppl) }

This query is a rewrite of Query #20 contained in the XMark Benchmark Suite to use group by. The query partitions the customers based on their income.

Result:

<challenge>4731</challenge>
<na>12677</na>
<preferred>314</preferred>
<standard>7778</standard>

In contrast to the relational GROUP BY statement, the XQuery counterpart concatenates the values of all non-grouping variables that belong to a specific group. In the context of our example, all nodes in //people/person that belong to the preferred partition are concatenated in $ppl after grouping has finished. You can see this effect by changing the return statement to:

 
...
return element { $income } { $ppl }

Result:

<challenge>
  <person id="person0">
    <name>Kasidit Treweek</name>
    …
  <person id="personX">
    …
</challenge>

Moreover, a value can be assigned to the grouping variable. This is shown in the following example:

XQuery:

let $data :=
  <xml>
    <person country='USA' name='John'/>
    <person country='USA' name='Jack'/>
    <person country='Germany' name='Johann'/>
  </xml>
for $person in $data/person
group by $country := $person/@country
return element persons {
  attribute country { $country },
  for $name in $person/@name
  return element name { data($name) }
}

Result:

<persons country="USA">
  <name>John</name>
  <name>Jack</name>
</persons>
<persons country="Germany">
  <name>Johann</name>
</persons>

count[edit]

The count clause enhances the FLWOR expression with a variable that enumerates the iterated tuples.

for $n in (1 to 10)[. mod 2 = 1]
count $c
return <number count="{ $c }" number="{ $n }"/>

allowing empty[edit]

The allowing empty provides functionality similar to outer joins in SQL:

for $n allowing empty in ()
return 'empty? ' || empty($n)

window[edit]

Window clauses provide a rich set of variable declarations to process sub-sequences of iterated tuples. An example:

for tumbling window $w in (2, 4, 6, 8, 10, 12, 14)
    start at $s when true()
    only end at $e when $e - $s eq 2
return <window>{ $w }</window>

More information on window clauses, and all other enhancements, can be found in the specification.

Function Items[edit]

One of the most distinguishing features added in XQuery 3.0 are function items, also known as lambdas or lambda functions. They make it possible to abstract over functions and thus write more modular code.

Examples:

Function items can be obtained in three different ways:

  • Declaring a new inline function:
    let $f := function($x, $y) { $x + $y }
    return $f(17, 25)

    Result: 42

  • Getting the function item of an existing (built-in or user-defined) XQuery function. The arity (number of arguments) has to be specified as there can be more than one function with the same name:
    let $f := math:pow#2
    return $f(5, 2)

    Result: 25

  • Partially applying another function or function item. This is done by supplying only some of the required arguments, writing the placeholder ? in the positions of the arguments left out. The produced function item has one argument for every placeholder.
    let $f := substring(?, 1, 3)
    return (
      $f('foo123'),
      $f('bar456')
    )

    Result: foo bar

Function items can also be passed as arguments to and returned as results from functions. These so-called Higher-Order Functions like for-each and fold-left are discussed in more depth on their own Wiki page.

Simple Map Operator[edit]

The simple map operator ! provides a compact notation for applying the results of a first to a second expression: the resulting items of the first expression are bound to the context item one by one, and the second expression is evaluated for each item. The map operator may be used as replacement for FLWOR expressions:

Example:

(: Simple map notation :)
(1 to 10) ! element node { . },
(: FLWOR notation :)
for $i in 1 to 10
return element node { $i }

In contrast to path expressions, the results of the map operator will not be made duplicate-free and returned in document order.

Try/Catch[edit]

The try/catch construct can be used to handle errors at runtime:

Example:

try {
  1 + '2'
} catch err:XPTY0004 {
  'Typing error: ' || $err:description
} catch * {
  'Error [' || $err:code || ']: ' || $err:description
}

Result: Typing error: '+' operator: number expected, xs:string found.

Within the scope of the catch clause, a number of variables are implicitly declared, giving information about the error that occurred:

  • $err:code error code
  • $err:description: error message
  • $err:value: value associated with the error (optional)
  • $err:module: URI of the module where the error occurred
  • $err:line-number: line number where the error occurred
  • $err:column-number: column number where the error occurred

Switch[edit]

The switch statement is available in many other programming languages. It chooses one of several expressions to evaluate based on its input value.

Example:

for $fruit in ("Apple", "Pear", "Peach")
return switch ($fruit)
  case "Apple" return "red"
  case "Pear"  return "green"
  case "Peach" return "pink"
  default      return "unknown"

Result: red green pink

The expression to evaluate can correspond to multiple input values.

Example:

for $fruit in ("Apple", "Cherry")
return switch ($fruit)
  case "Apple"
  case "Cherry"
     return "red"
  case "Pear"
     return "green"
  case "Peach"
     return "pink"
  default
     return "unknown"

Result: red red

Expanded QNames[edit]

A QName can be prefixed with the letter Q, the namespace URI wrapped in curly braces and the local name.

Examples:

  • Q{http://www.w3.org/2005/xpath-functions/math}pi() returns the number π
  • Q{java:java.io.FileOutputStream}new("output.txt") creates a new Java file output stream

Namespace Constructors[edit]

New namespaces can be created via so-called 'Computed Namespace Constructors'.

 
element node { namespace pref { 'http://url.org/' } }

String Concatenations[edit]

Two vertical bars || (also named pipe characters) can be used to concatenate strings. This operator is a shortcut for the concat() function.

 
'Hello' || ' ' || 'Universe'

External Variables[edit]

Default values can be attached to external variable declarations. This way, an expression can also be evaluated if its external variables have not been bound to a new value.

 
declare variable $user external := "admin";
"User:", $user

Serialization[edit]

Serialization parameters can be defined within XQuery expressions. Parameters are placed in the query prolog and need to be specified as option declarations, using the output prefix.

Example:

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:omit-xml-declaration "no";
declare option output:method "xhtml";
<html/>

Result: <?xml version="1.0" encoding="UTF-8"?><html></html>

In BaseX, the output prefix is statically bound and can thus be omitted. Note that all namespaces need to be specified when using external APIs, such as XQJ.

Context Item[edit]

The context item can be specified in the prolog of an XQuery expression:

Example:

declare context item := document {
  <xml>
    <text>Hello</text>
    <text>World</text>
  </xml>
};

for $t in .//text()
return string-length($t)

Result: 5 5

Annotations[edit]

XQuery 3.0 introduces annotations to declare properties associated with functions and variables. For instance, a function may be declared %public, %private, or %updating.

Example:

declare %private function local:max($x1, $x2) {
  if($x1 > $x2) then $x1 else $x2
};

local:max(2, 3)

Functions[edit]

The following functions have been added in the XQuery 3.0 Functions and Operators Specification:

analyze-string, available-environment-variables, element-with-id, environment-variable, filter, fold-left, fold-right, for-each, for-each-pair, format-date, format-dateTime, format-integer, format-number, format-time, function-arity, function-lookup, function-name, generate-id, has-children, head, innermost, outermost, parse-xml, parse-xml-fragment, path, serialize, tail, unparsed-text, unparsed-text-available, unparsed-text-lines, uri-collection

New signatures have been added for the following functions:

document-uri, string-join, node-name, round, data

Changelog[edit]

Version 7.7
Version 7.3
Version 7.2
Version 7.1
Version 7.0