Constructors and Conditionals

Constructors and Conditional Expressions

Direct constructors look like the XML they produce, with { } enclosing expressions in content and attribute values. Computed constructors (element {name} {content}, attribute, text, comment, processing-instruction, namespace, document) take names from data. if (...) then ... else ... always needs its else. XQuery 3.1's string constructor `` [ ... ] ` is a template with { expr } ` holes:

constructors.xq: direct and computed constructors, a conditional, a template
(: Direct and computed constructors, a conditional, and a string constructor :)
<shelf books="{count(//book)}">{
  for $b in //book[position() le 2]
  let $p := xs:decimal($b//price)
  return <item sku="{$b/identifier}" band="{if ($p ge 20) then 'premium' else 'standard'}">{
    attribute rating { $b/rating },
    element { "price-" || lower-case($b//price/@currency) } { $p },
    $b/title/string()
  }</item>
}<note>Literal braces: {{ and }}; quotes: &quot; and &#39;</note></shelf>,
``[First title: `{ (//book)[1]/title }`, out of stock: `{ //book[.//availability
  = "out-of-stock"]/@id }`]``
Running the constructor query
xquery -s:booknest-catalog.xml constructors.xq '!indent=yes'
Output
<shelf books="6">
   <item sku="BN-0001" band="standard" rating="4.6">
      <price-usd>14.99</price-usd>The Quiet Harbor</item>
   <item sku="BN-0002" band="premium" rating="4.3">
      <price-usd>39.5</price-usd>Patterns of the Deep Web</item>
   <note>Literal braces: { and }; quotes: " and '</note>
</shelf>
"First title: The Quiet Harbor, out of stock: b3"

The computed attribute must come before any child node of its element, and the element name price-usd came from data. Inside content, a literal brace is written twice; in string literals, quotes are doubled or written as &quot; and &#39; (some references give &#34; for the apostrophe, but that is the double quote).


Other Expressions

Besides FLWOR, XQuery supports a range of other expressions: node constructors, partial function application, windowing, error handling, and prolog declarations.

Node constructors

Direct and computed constructors build comments, elements, namespaces, attributes, and text nodes.
ch05-node-constructors.xq
comment{'This shows the use of various constructors'},
'&#10;',
element student {
    namespace school {'http://tchs.example.com'},
    attribute id {'U027218N'},
    text {'&#10;1. '},
    element firstName {'Chong'},
    element lastName {'Lip Phang'}}
Output
<!--This shows the use of various constructors-->
<student xmlns:school="http://tchs.example.com" id="U027218N">
1. <firstName>Chong</firstName><lastName>Lip Phang</lastName></student>

Partial function application

A placeholder argument (?) fixes some arguments of a function while leaving others open, producing a new function.
ch05-partial-function.xq
let $f := substring(?,1,3)
return (
   $f('cat123'),
   $f('dog456')
)
Output
cat dog

allowing empty

The allowing empty keyword on a for clause makes the loop run once with the variable bound to an empty sequence when the source sequence is empty, instead of producing no results at all.
ch05-allowing-empty.xq
for $n allowing empty at $i in (300,200,100,())
return ($n,$i,'&#10;')
Output
300 1
200 2
100 3

Tumbling and sliding windows

A for tumbling window clause partitions a sequence into consecutive, non-overlapping windows. Each window starts where the previous one ended.
ch05-tumbling-window.xq
for tumbling window $w in (20,40,60,80,100,120,140)
start at $s when true()
only end at $e when $e - $s = 2
return <window>{$w}</window>
Output
<window>20 40 60</window>
<window>80 100 120</window>
A for sliding window clause instead advances one item at a time, so windows overlap.
ch05-sliding-window.xq
for sliding window $w in (20,40,60,80,100,120,140)
start at $s when true()
only end at $e when $e - $s = 2
return <window>{$w}</window>
Output
<window>20 40 60</window>
<window>40 60 80</window>
<window>60 80 100</window>
<window>80 100 120</window>
<window>100 120 140</window>

try/catch

Errors can be caught by specific error code (in the standard err namespace, http://www.w3.org/2005/xqt-errors 189 ) or by a wildcard catch *, which exposes $err:code, $err:description, $err:value, $err:module, $err:line-number, and $err:additional.
ch05-try-catch.xq
declare namespace err = "http://www.w3.org/2005/xqt-errors";
try {
   3 div 0
} catch err:XPTY0004 {
   'typing error'
} catch * {
   $err:code || '&#10;' ||
   $err:description || '&#10;' ||
   $err:value || '&#10;' ||
   $err:module || '&#10;' ||
   $err:line-number || '&#10;' ||
   $err:additional
}
Output
err:FOAR0001
division_by_zero
0
file:///C:/Zend/Apache2/htdocs/xml/richestMen.xq
3

switch

Compares one expression against multiple case values, falling through to default if none match. Adjacent case clauses sharing one return act as an "or".
ch05-switch.xq
switch (5)
   case 3
   case 5 return "three or five"
   case 7 return "seven"
   default return "unknown"
Output
three or five

External variables and URIQualifiedName function calls

A variable declared external can be initialized from a function referenced by its full namespace URI in braces (a URIQualifiedName), without an import module.
ch05-external-variable.xq
declare variable $pi external :=
         Q{http://www.w3.org/2005/xpath-functions/math}pi();
$pi
Output
3.14159265358979

Serialization options

declare option output:..., using the standard serialization namespace (http://www.w3.org/2010/xslt-xquery-serialization 189 ), controls how the query's result is serialized: XML declaration, output method, encoding, indentation, and item separator.
ch05-serialization-options.xq
declare namespace
output = "http://www.w3.org/2010/xslt-xquery-serialization";

declare option output:omit-xml-declaration "no";
declare option output:method "xml";
declare option output:encoding "iso-8859-1";
declare option output:indent "yes";
declare option output:item-separator "&#10;";
<html/>
Output
<?xml version="1.0" encoding="iso-8859-1"?><html/>

Context item declaration

declare context item := sets the initial context item (here, a constructed document) that a path expression such as //text() then operates on, without a preceding for.
ch05-context-item.xq
declare context item := document {
   <person>
      <firstName>Lin</firstName>
      <lastName>Dan</lastName>
   </person>
};
//text()
Output
LinDan

%private annotation

A variable or function declared with the %private annotation is hidden from any module that imports the containing module.
ch05-private-annotation.xq
(: A private variable/function is hidden from module import. :)
declare %private variable $v := 10;
declare %private function local:mult2($x) {$x * 2};
local:mult2($v)
Output
20

Schema and module import

import schema namespace brings in type definitions from an XSD; import module namespace brings in functions and variables from another XQuery module.
ch05-schema-module-import.xq
import schema namespace
  geometry = "http://example.org/geo-schema-declarations";

import module namespace
  geo = "http://example.org/geo-functions";

declare variable
  $t as geometry:triangle := geo:make-triangle();

$t

Decimal formats

declare decimal-format defines a named set of characters (decimal separator, grouping separator, and more) that format-number can then use by name, letting the same number be formatted for different locales.
ch05-decimal-format.xq
declare decimal-format local:de
      decimal-separator = ","
      grouping-separator = ".";

declare decimal-format local:en
      decimal-separator = "."
      grouping-separator = ",";

let $numbers := (1234.567, 789, 1234567.765)

for $i in $numbers

return (

  format-number($i, "#.###,##", "local:de"),

  format-number($i, "#,###.##", "local:en")

)
Output
1.234,57 1,234.57 789 789 1.234.567,76 1,234,567.76

More prolog declarations

The query prolog can additionally declare the XQuery version and encoding, a module namespace, whitespace/collation/base-URI/construction/ordering defaults, namespace copying behavior on element construction, and default element/function namespaces. See https://www.w3.org/TR/2014/REC-xquery-30-20140408/#id-query-prolog 189 .
ch05-prolog-declarations.xq
(: more prolog declarations :)
(: http://www.w3.org/TR/2014/REC-xquery-30-20140408/#id-query-prolog :)

xquery version "3.0" encoding "utf-8";
module namespace gis = "http://example.org/gis-functions";
declare boundary-space preserve;
declare default collation
      "http://example.org/languages/Icelandic";
declare base-uri "http://example.org";
declare construction strip;
declare ordering unordered;
declare default order empty least;
declare copy-namespaces preserve, no-inherit;
declare default element namespace
      "http://example.org/names";
declare default function namespace
      "http://www.w3.org/2005/xpath-functions/math";