This document covers some advanced XQuery usage. This functionality is
partly tied to using Tamino query pragmas that affect the processing of the
query. With Tamino query pragmas you can import modules and add declarations
for namespaces and collations as well as functions and external variables. They
have the syntactic form {?piname?}
, which is why they were
previously called XQuery processing instructions. This document discusses
some of these concepts:
Another important area of advanced XQuery usage is related to performance questions and optimizing your Tamino XQuery programs. You can find more information about this topic in the Performance Guide.
A namespace declaration defines a namespace prefix and associates it with a valid namespace URI. This namespace declaration is valid throughout the query expression. For example, you can define your own namespace:
declare namespace dotcom="http://company.dot.com/namespaces/corporate" for $a in input()/bib/book return <dotcom:bookshelf> { $a } </dotcom:bookshelf>
It is an error (INOXQE 6356) to redefine a namespace:
declare namespace dotcom="http://company.dot.com/namespaces/corporate" declare namespace dotcom="http://company.dot.com/new-namespaces/corporate" for $a in input()/bib/book return <dotcom:bookshelf> { $a } </dotcom:bookshelf>
But you can use two different namespaces at the same time:
declare namespace dotcom="http://company.dot.com/namespaces/corporate" declare namespace tf="http://namespaces.softwareag.com/tamino/TaminoFunction" for $a in input()/bib/book where tf:containsText($a/title, "UNIX") return <dotcom:bookshelf> { $a } </dotcom:bookshelf>
You can also declare default namespaces that can be applied to elements or attributes alike.
declare default element namespace "http://company.dot.com/namespaces/corporate" for $a in input()/bib/book return <bookshelf> { $a } </bookshelf>
The default element namespace applies to all unqualified element names, in both expressions and constructors, unless a different default namespace is defined in an inner scope, as shown in the following example:
declare default element namespace "X" declare namespace y="Y" let $x := <x1>{element x2{<x3 xmlns="Y">{element x4{}}</x3>}}</x1> return $x/x2/y:x3/y:x4
In this example, the default element namespace applies to all
occurrences of x1
and x2
;
however, it does not apply to x3
and
x4
, because their default namespace is defined by
the inner specification xmlns="Y"
.
The default element namespace does not apply to attribute names.
There is no default attribute namespace.
There is a default function namespace. It applies to function names in function definitions and function calls.
Tip:
You need not declare a namespace in the prolog if you use one of the
predeclared namespaces. You can find the list of predeclared namespaces in the
description of NamespaceDecl
in the XQuery Reference Guide
In addition to the large set of XQuery functions as defined by the W3C
and those that are specific to Tamino, you can write your own functions.
User-defined functions consist of a function header representing its signature
and the function body containing an XQuery expression. The header consists of
an identifier, a list of parameters and corresponding type information, and the
type of the return value. Type information is optional: if you omit it,
item*
will be assumed. Note that the set of allowed types is
restricted to all simple types and some common XQuery types (the reference
description of FunctionDecl contains a
complete list).
The function identifier must be a QName together with a non-empty
namespace prefix. To avoid introducing a new namespace for locally used
functions, that is functions used in the current module, XQuery provides an
implicit namespace to which the prefix local
is bound. This is an
example for a function that uses this local namespace:
declare function local:siblings($a as element()) as element()* { for $x in $a/../* where not($x is $a) return $x } let $a := <a> <a1>foo</a1> <a2>bar</a2> </a> return local:siblings($a/a1)
It takes an element node as argument and returns all its sibling element
nodes. Following the function declaration it is directly used in a query body
resulting in the node <a2>bar</a2>
.
User-defined functions may be recursive, that is a function can contain a call to itself:
declare function local:depth($e as node()) as xs:integer { if (not($e/*)) then 1 else max(for $c in $e/* return local:depth($c)) + 1 }
This function computes the depth of a node by calling itself for its children nodes.
To avoid running out of memory during the execution of a user-defined function, the XQuery processor restricts the amount of memory that can be used by a single query processing thread during query execution. The amount of memory can be modified by an XQuery pragma. Similarly, you can avoid a stack overflow by restricting the call stack of the function. The following pragma sets the available memory to 100 MB and the maximum call stack depth to 1000 (default value is 256):
{?execution memory="100" call-stack-depth="1000"?}
Note:
See also the Performance Guide for information about optimizing
user-defined functions using inlining techniques.
In XQuery, code can be organized into modules. There are two principal kinds of modules: a main module that contains the query body, and library modules that you can import into other library modules or into the main module. For example, you can put the functions defined in the last section into a module of its own:
module namespace tree="http://www.examples.com/tree" declare function tree:depth($e as node()) as xs:integer { if (not($e/*)) then 1 else max(for $c in $e/* return tree:depth($c)) + 1 } declare function tree:siblings($a as element()) as element()* { for $x in $a/../* where not($x is $a) return $x }
Before you can use the functions defined in a library module, you must
store the module at a special place to make it directly accessible to the
XQuery processor. In Tamino, modules are stored in the system collection
ino:source
. From a module definition, some meta data is derived to
provide access to module properties that are relevant for efficient lookup of
modules and user-defined functions. The meta data also simplifies querying
module properties in order to generate interface descriptions such as WSDL
definitions.
Modules are stored as non-XML data in the ino:module
doctype of the ino:source
collection. This way you can define
modules using the _process
command and remove them with
_delete
. Alternatively, you can use the Tamino Interactive
Interface.
Note that a library module must not contain variable declarations. Also, Tamino query pragmas which are directives to the query processor are not allowed.
To use a module, you must import it with an import statement. Consider using the library of tree functions:
import module namespace tree="http://www.examples.com/tree" let $a := <a> <a1>foo</a1> <a2>bar</a2> </a> return tree:siblings($a/a1)
This import statement imports the module with the target namespace http://www.examples.com/tree. Note that you cannot import the same module more than once.
To check for existing modules, you can query the ino:source
collection in the following way to retrieve the non-XML data of all modules of
a given namespace:
declare namespace ino="http://namespaces.softwareag.com/tamino/response2" root( for $a in collection("ino:source")/ino:module where $a/@ino:targetNamespace="http://www.examples.com/tree" return $a )
The query functions defined in an XQuery module may also be used for defining a computed index. For details on computed indexes please refer to Performance Guide > Advanced Indexes.
The XQuery Tool delivered with Tamino provides convenient support for maintaining XQuery modules.
When Tamino executes a query, it handles the query in terms of its data
model: an XML document is treated as a tree with a document root and different
types of nodes. The query result is then serialized and wrapped into a
Tamino response document. You can determine the serialization by using a Tamino
query pragma, or XQuery processing instruction, which always has the form
{?piname?}
. Like a regular XML processing instruction, it can have
additional information. This section discusses the available
serializations:
Normally, when Tamino executes a query, it returns the result using a response wrapper. This is the result of the very first query in this manual:
You can, however, suppress the response wrapper so that you get the bare result by using the serialization pragma and choosing the method "xml":
{?serialization method="xml"?} <fact> This section contains { 3 + 6 } examples.</fact>
The output is then much shorter and is restricted to the query result as such:
<fact>This section contains 9 examples.</fact>
Using {?serialization method="xml"?}
always implies that
"text/xml" is used as media type for the response
document. You can change this by adding
media-type
. The following query returns a
literal SVG document which has the media type
"image/svg+xml":
{?serialization method="xml" media-type="image/svg+xml"?} <svg width="200" height="200"> <circle cx="100" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/> </svg>
This delivers the SVG document with the appropriate MIME media type
which is then set in the HTTP response header contentType
. It also
means that the normal response wrapper is not used.
You can define your own method of delivering the response document by using a server extension (SXS) as output handler. This output handler will then act in place of the internal Tamino XQuery processor. In general you use:
{?serialization method="<outputHandler>" parameter="<outputHandlerParameter>"?}
For example, this allows using the XSLT server extension to transform query results on-the-fly:
{?serialization method="XSLT.transform" parameter="stylesheets" parameter="stylesheets/patientRecords.xsl"?} <report> { for $a in collection('Hospital')/patient return <patient>{ $a/name, $a/sex, $a/born, $a/address }</patient> } </report>
The method
attribute identifies the
output handler. The two parameters specify the XSL stylesheet to be used and
the query. Tamino then passes the query result, the list of patients, to this
output handler which transforms it using the stylesheet
patientRecords.xsl.
Please note that you can also use
media-type
in the serialization pragma for an
output handler.
For certain operations on strings such as comparison or sort operations
collations are used. They inherently determine the result of a comparison to
accommodate for special regional purposes or linguistic needs. If a collation
is not defined, Tamino uses Unicode codepoints for performing these operations.
There are two ways to use collations: In the schema you can add collation
information per element by using tsd:collation
.
In addition, you can assign a default collation in the query prolog such
as:
declare default collation "collation?language=fr"
The string literal is the collation URI which is interpreted as relative URL with the base URI http://www.softwareag.com/tamino. In this example, the collation defined for the French language is used.
You can use the Tamino-specific XQuery function
tf:getCollation
to deploy collations as in the following
query:
for $i in input()/patient/name where compare($i/surname, 'Müller', tf:getCollation($i/surname)) = 0 return $i
This query returns those name
elements whose
surname
child element has a contents that is
compared equal to the string "Müller" using the
collation information defined in the Tamino schema for
surname
elements.
Please see also the section Collations in the Tamino XML Schema User Guide for details about collation definitions in schemata.