:
If the expanded QName returned by the atomized name expression has a namespace URI but has no prefix, it is given an implementation-dependent prefix.
The resulting expanded QName (including its prefix) is
used as the node-name
property of the constructed
attribute node.
If the atomized value of the name expression is of type
xs:string
or xs:untypedAtomic
, that value
is converted to an expanded QName. If the string value
contains a namespace prefix, that prefix is resolved to a namespace
URI using the statically known namespaces. If the
string value contains no namespace prefix, it is treated as a local
name in no namespace. The resulting expanded QName (including its prefix) is
used as the node-name
property of the constructed
attribute. If conversion of the atomized name expression to an expanded QName is
not successful, a dynamic error is raised [err:XQDY0074].
A dynamic error is raised [err:XQDY0044] if the node-name of the constructed attribute node has any of the following properties:
Its namespace prefix is xmlns
.
It has no namespace prefix and its local name is
xmlns
.
Its namespace URI is
http://www.w3.org/2000/xmlns/
.
Its namespace prefix is xml
and its namespace URI
is not http://www.w3.org/XML/1998/namespace
.
Its namespace prefix is other than xml
and its
namespace URI is
http://www.w3.org/XML/1998/namespace
.
The content expression of a computed attribute constructor is processed as follows:
Atomization is applied to the result of the content expression, converting it to a sequence of atomic values. (If the content expression is absent, the result of this step is an empty sequence.)
If the result of atomization is an empty sequence, the value of the attribute is the zero-length string. Otherwise, each atomic value in the atomized sequence is cast into a string.
The individual strings resulting from the previous step are
merged into a single string by concatenating them with a single
space character between each pair. The resulting string becomes the
string-value
property of the new attribute node. The
type
annotation (type-name
property) of the new
attribute node is xs:untypedAtomic
. The
typed-value
property of the attribute node is the same
as its string-value
, as an instance of
xs:untypedAtomic
.
The parent
property of the attribute node is set to
empty.
If the attribute name is xml:id
, then
xml:id
processing is performed as defined in [XML ID]. This ensures that the attribute node has the
type xs:ID
and that its value is properly normalized.
If an error is encountered during xml:id
processing,
an implementation may raise a dynamic error [err:XQDY0091].
If the attribute name is xml:id
, the
is-id
property of the resulting attribute node is set
to true
; otherwise the is-id
property is
set to false
. The is-idrefs
property of
the attribute node is unconditionally set to
false
.
If the attribute name is xml:space
and the
attribute value is other than preserve
or
default
, a dynamic error may be raised [err:XQDY0092].
Example:
attribute size {4 + 3}
The string
value of the size
attribute is "7
"
and its type is xs:untypedAtomic
.
Example:
attribute { if ($sex = "M") then "husband" else "wife" } { Hello, 1 to 3, Goodbye }
The name of the constructed attribute is either
husband
or wife
. Its string value is
"Hello 1 2 3 Goodbye
".
| [152] | CompDocConstructor |
::= | "document" "{" Expr
"}" |
All document node constructors are computed constructors. The result of a document node constructor is a new document node, with its own node identity.
A document node constructor is useful when the result of a query
is to be a document in its own right. The following example
illustrates a query that returns an XML document containing a root
element named author-list
:
document { <author-list> {fn:doc("bib.xml")/bib/book/author} </author-list> }
The content expression of a document node constructor is processed in exactly the same way as an enclosed expression in the content of a direct element constructor, as described in Step 1e of <IP_ADDRESS> Content. The result of processing the content expression is a sequence of nodes called the content sequence. Processing of the document node constructor then proceeds as follows:
If the content sequence contains a document node, the document node is replaced in the content sequence by its children.
Adjacent text nodes in the content sequence are merged into a single text node by concatenating their contents, with no intervening blanks. After concatenation, any text node whose content is a zero-length string is deleted from the content sequence.
If the content sequence contains an attribute node, a type error is raised [err:XPTY0004].
If the content sequence contains a namespace node, a type error is raised [err:XPTY0004].
The properties of the newly constructed document node are determined as follows:
base-uri
is set to the Static Base
URI.
children
consist of all the element, text, comment,
and processing instruction nodes in the content sequence. Note that
the parent
property of each of these nodes has been
set to the newly constructed document node.
The unparsed-entities
and document-uri
properties are empty.
The string-value
property is equal to the
concatenated contents of the text-node descendants in document
order.
The typed-value
property is equal to the
string-value
property, as an instance of
xs:untypedAtomic
.
No validation is performed on the constructed document node. The [XML 1.0] rules that govern the structure of an XML document (for example, the document node must have exactly one child that is an element node) are not enforced by the XQuery document node constructor.
| [160] | CompTextConstructor |
::= | "text" "{" Expr
"}" |
All text node constructors are computed constructors. The result of a text node constructor is a new text node, with its own node identity.
The content expression of a text node constructor is processed as follows:
Atomization is applied to the value of the content expression, converting it to a sequence of atomic values.
If the result of atomization is an empty sequence, no text node is constructed. Otherwise, each atomic value in the atomized sequence is cast into a string.
The individual strings resulting from the previous step are
merged into a single string by concatenating them with a single
space character between each pair. The resulting string becomes the
content
property of the constructed text node.
The parent
property of the constructed text node is
set to empty.
Note:
It is possible for a text node constructor to construct a text node containing a zero-length string. However, if used in the content of a constructed element or document node, such a text node will be deleted or merged with another text node.
The following example illustrates a text node constructor:
text {"Hello"}
| [162] | CompPIConstructor |
::= | "processing-instruction" (NCName | ("{" Expr "}")) "{" Expr? "}" |
A computed processing instruction constructor (CompPIConstructor) constructs a new processing instruction node with its own node identity.
If the keyword processing-instruction
is followed
by an NCName, that NCName is used as the target
property of the constructed node. If the keyword
processing-instruction
is followed by a name expression,
the name expression is processed as follows:
Atomization is
applied to the value of the name expression. If the result of
atomization is
not a single atomic value of type xs:NCName
,
xs:string
, or xs:untypedAtomic
, a
type error is
raised [err:XPTY0004].
If the atomized value of the name expression is of type
xs:string
or xs:untypedAtomic
, that value
is cast to the type xs:NCName
. If the value cannot be
cast to xs:NCName
, a dynamic error is raised [err:XQDY0041].
The resulting NCName is then used as the target
property of the newly constructed processing instruction node.
However, a dynamic error is raised if the NCName is
equal to "XML
" (in any combination of upper and lower
case) [err:XQDY0064].
The content expression of a computed processing instruction constructor is processed as follows:
Atomization is applied to the value of the content expression, converting it to a sequence of atomic values. (If the content expression is absent, the result of this step is an empty sequence.)
If the result of atomization is an empty sequence, it is
replaced by a zero-length string. Otherwise, each atomic value in
the atomized sequence is cast into a string. If any of the
resulting strings contains the string "?>
", a
dynamic error
[err:XQDY0026] is
raised.
The individual strings resulting from the previous step are
merged into a single string by concatenating them with a single
space character between each pair. Leading whitespace is removed
from the resulting string. The resulting string then becomes the
content
property of the constructed processing
instruction node.
The remaining properties of the new processing instruction node are determined as follows:
The parent
property is empty.
The base-uri
property is empty.
The following example illustrates a computed processing instruction constructor:
let $target := "audio-output", $content := "beep" return processing-instruction {$target} {$content}
The processing instruction node constructed by this example might be serialized as follows:
<?audio-output beep?>
| [161] | CompCommentConstructor |
::= | "comment" "{" Expr
"}" |
A computed comment constructor (CompCommentConstructor) constructs a new comment node with its own node identity. The content expression of a computed comment constructor is processed as follows:
Atomization is applied to the value of the content expression, converting it to a sequence of atomic values.
If the result of atomization is an empty sequence, it is replaced by a zero-length string. Otherwise, each atomic value in the atomized sequence is cast into a string.
The individual strings resulting from the previous step are
merged into a single string by concatenating them with a single
space character between each pair. The resulting string becomes the
content
property of the constructed comment node.
It is a dynamic error [err:XQDY0072] if the result of the content expression of a computed comment constructor contains two adjacent hyphens or ends with a hyphen.
The parent
property of the constructed comment node
is set to empty.
The following example illustrates a computed comment constructor:
let $homebase := "Houston" return comment {fn:concat($homebase, ", we have a problem.")}
The comment node constructed by this example might be serialized as follows:

| [156] | CompNamespaceConstructor |
::= | "namespace" (Prefix |
("{" PrefixExpr "}")) "{"
URIExpr "}" |
| [158] | PrefixExpr |
::= | Expr |
| [159] | URIExpr |
::= | Expr |
A computed namespace constructor creates a new namespace node, with its own node identity. The parent of the newly created namespace node is empty.
If the constructor specifies a Prefix
, it is used
as the prefix for the namespace node.
If the constructor specifies a PrefixExpr
, the
prefix expression is evaluated as follows:
Atomization is
applied to the result of the PrefixExpr
.
If the result of atomization is an empty sequence or a single
atomic value of type xs:string
or
xs:untypedAtomic
, then the following rules are applied
in order:
If the result is castable to xs:NCName
, then it is
used as the local name of the newly constructed namespace node.
(The local name of a namespace node represents the prefix part of
the namespace binding.)
If the result is the empty sequence or a zero-length
xs:string
or xs:untypedAtomic value, the new namespace
node has no name (such a namespace node represents a binding for
the default namespace).
Otherwise, a dynamic error is raised [err:XQDY0074].
If the result of atomization is not an empty sequence or a
single atomic value of type xs:string
or
xs:untypedAtomic
, a type error is raised [err:XPTY0004].
The URIExpr
is evaluated, and the result is cast to
xs:anyURI
to create the URI
property for
the newly created node. An implementation may raise a dynamic
error [err:XQDY0074] if the URIExpr
of a
computed namespace constructor is not a valid instance of
xs:anyURI
.
An error [err:XQDY0101] is raised if a computed namespace constructor attempts to do any of the following:
Bind the prefix xml
to some namespace URI other
than http://www.w3.org/XML/1998/namespace
.
Bind a prefix other than xml
to the namespace URI
http://www.w3.org/XML/1998/namespace
.
Bind the prefix xmlns
to any namespace URI.
Bind a prefix to the namespace URI
http://www.w3.org/2000/xmlns/
.
Bind any prefix (including the empty prefix) to a zero-length namespace URI.
By itself, a computed namespace constructor has no effect on in-scope namespaces, but if an element constructor's content sequence contains a namespace node, the namespace binding it represents is added to the elements in-scope namespaces.
A computed namespace constructor has no effect on the statically known namespaces.
Note:
The newly created namespace node has all properties defined for a namespace node in the data model. Like all nodes, it has identity. Like all nodes which do not share a common parent, the relative order of these nodes is implementation dependent. As defined in the data model, the name of the node is the prefix, and the string value of the node is the URI.
Examples:
A computed namespace constructor with a prefix:
namespace a {"http://a.example.com" }
A computed namespace constructor with a prefix expression:
namespace {"a"} {"http://a.example.com" }
A computed namespace constructor with an empty prefix:
namespace { "" } {"http://a.example.com" }
Computed namespace constructors are generally used to add to the in-scope namespaces of elements created with element constructors:
<age xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> { namespace xs {"http://www.w3.org/2001/XMLSchema"}, attribute xsi:type {"xs:integer"}, 23 }</age>
In the above example, note that the xsi
namespace
binding is created for the element because it is used in an
attribute name. The attribute's content is simply character data,
and has no effect on namespace bindings. The computed namespace
constructor ensures that the xs
binding is
created.
Computed namespace constructors have no effect on the statically known namespaces. If the prefix a is not already defined in the statically known namespaces, the following expression results in a static error [err:XPST0081].
 { namespace a { "http://a.example.com" } }
An element node constructed by a direct or computed element
constructor has an in-scope namespaces property that
consists of a set of namespace bindings. The in-scope
namespaces of an element node may affect the way the node is
serialized (see 2.2.4
Serialization), and may also affect the behavior of certain
functions that operate on nodes, such as fn:name
. Note
the difference between in-scope namespaces, which is a
dynamic property of an element node, and statically known namespaces, which is a
static property of an expression. Also note that one of the
namespace bindings in the in-scope namespaces may have no prefix
(denoting the default namespace for the given element). The
in-scope namespaces of a constructed element node consist of the
following namespace bindings:
A namespace binding is created for each namespace declared in the current element constructor by a namespace declaration attribute.
A namespace binding is created for each namespace node in the content sequence of the current element constructor.
A namespace binding is created for each namespace that is declared in a namespace declaration attribute of an enclosing direct element constructor and not overridden by the current element constructor or an intermediate constructor.
A namespace binding is always created to bind the prefix
xml
to the namespace URI
http://www.w3.org/XML/1998/namespace
.
For each prefix used in the name of the constructed element or in the names of its attributes, a namespace binding must exist. If a namespace binding does not already exist for one of these prefixes, a new namespace binding is created for it. If this would result in a conflict, because it would require two different bindings of the same prefix, then the prefix used in the node name is changed to an arbitrary implementation-dependent prefix that does not cause such a conflict, and a namespace binding is created for this new prefix. If there is an in-scope default namespace, then a binding is created between the empty prefix and that URI.
Note:
Copy-namespaces mode does not affect the namespace bindings of a newly constructed element node. It applies only to existing nodes that are copied by a constructor expression.
In an element constructor, if two or more namespace bindings in the in-scope bindings would have the same prefix, then an error is raised if they have different URIs [err:XQDY0102]; if they would have the same prefix and URI, duplicate bindings are ignored.
The following query serves as an example:
declare namespace p="http://example.com/ns/p"; declare namespace q="http://example.com/ns/q"; declare namespace f="http://example.com/ns/f";

The in-scope namespaces of the resulting
p:a
element consists of the following namespace
bindings:
p = "http://example.com/ns/p"
q = "http://example.com/ns/q"
r = "http://example.com/ns/r"
xml = "http://www.w3.org/XML/1998/namespace"
The namespace bindings for p
and q
are
added to the result element because their respective namespaces are
used in the names of the element and its attributes. The namespace
binding r="http://example.com/ns/r"
is added to the
in-scope namespaces of the constructed element because it is
defined by a namespace declaration attribute, even
though it is not used in a name.
No namespace binding corresponding to
f="http://example.com/ns/f"
is created, because the
namespace prefix f
appears only in the query prolog
and is not used in an element or attribute name of the constructed
node. This namespace binding does not appear in the query result,
even though it is present in the statically known namespaces and is
available for use during processing of the query.
Note that the following constructed element, if nested within a
validate
expression, cannot be validated:

3

The constructed element will have namespace bindings for the
prefixes xsi
(because it is used in a name) and
xml
(because it is defined for every constructed
element node). During validation of the constructed element, the
validator will be unable to interpret the namespace prefix
xs
because it is has no namespace binding. Validation
of this constructed element could be made possible by providing a
namespace declaration attribute, as
in the following example:

3

XQuery provides a versatile expression called a FLWOR expression
that may contain multiple clauses. The FLWOR expression can be used
for many purposes, including iterating over sequences, joining
multiple documents, and performing grouping and aggregation. The
name FLWOR, pronounced "flower", is suggested by the keywords
for
, let
, where
, order
by
, and return
, which introduce some of the
clauses used in FLWOR expressions (but this is not a complete list
of such clauses.)
The complete syntax of a FLWOR expression is shown here, and relevant parts of the syntax are repeated in subsequent sections of this document.
The semantics of FLWOR expressions are based on a concept called
a tuple stream. [Definition: A
tuple stream is an ordered sequence of zero or more
tuples.] [Definition: A tuple is a set of zero or
more named variables, each of which is bound to a value that is an
XDM
instance.] Each tuple stream is homogeneous in the sense that
all its tuples contain variables with the same names and the same
static types. The
following example illustrates a tuple stream consisting of four
tuples, each containing three variables named $x
,
$y
, and $z
:
($x = 1003, $y = "Fred", $z = <age>21</age>) ($x = 1017, $y = "Mary", $z = <age>35</age>) ($x = 1020, $y = "Bill", $z = <age>18</age>) ($x = 1024, $y = "John", $z = <age>29</age>)
Note:
In this section, tuple streams are represented as shown in the above example. Each tuple is on a separate line and is enclosed in parentheses, and the variable bindings inside each tuple are separated by commas. This notation does not represent XQuery syntax, but is simply a representation of a tuple stream for the purpose of defining the semantics of FLWOR expressions.
Tuples and tuple streams are not part of the data model. They exist only as conceptual intermediate results during the processing of a FLWOR expression.
A FLWOR expression consists of an initial clause, zero or more intermediate clauses, and a final clause. Conceptually, the initial clause generates a tuple stream. Each intermediate clause takes the tuple stream generated by the previous clause as input and generates a (possibly different) tuple stream as output. The final clause takes a tuple stream as input and, for each tuple in this tuple stream, generates an XDM instance; the final result of the FLWOR expression is the ordered concatenation of these XDM instances.
The initial clause in a FLWOR expression may be a
for
, let
, or
window
clause. Intermediate clauses may be
for
, let
, window
,
count
, where
, group by
, or
order by
clauses. These intermediate clauses may be
repeated as many times as desired, in any order. The final clause
of the FLWOR expression must be a return
clause. The
semantics of the various clauses are described in the following
sections.
The following clauses in FLWOR expressions bind values to
variables: for
, let
, window
,
count
, and group by
. The binding of
variables for for
, let
, and
count
is governed by the following rules (the
binding of variables in group by
is discussed in
3.10.7 Group By Clause,
the binding of variables in window
clauses is
discussed in 3.10.4 Window
Clause):
The scope of a bound variable includes all subexpressions of the
containing FLWOR that appear after the variable binding. The scope
does not include the expression to which the variable is bound. The
following code fragment, containing two let
clauses,
illustrates how variable bindings may reference variables that were
bound in earlier clauses, or in earlier bindings in the same
clause:
let $x := 47, $y := f($x) let $z := g($x, $y)
A given variable may be bound more than once in a FLWOR expression, or even within one clause of a FLWOR expression. In such a case, each new binding occludes the previous one, which becomes inaccessible in the remainder of the FLWOR expression.
[Definition: A variable binding may be
accompanied by a type declaration, which consists of the
keyword as
followed by the static type of the
variable, declared using the syntax in 2.5.4 SequenceType Syntax.] At
run time, if the value bound to the variable does not match the
declared type according to the rules for SequenceType matching, a type error is raised
[err:XPTY0004]. For
example, the following let
clause raises a type error because the
variable $salary
has a type declaration that is not
satisfied by the value that is bound to it:
let $salary as xs:decimal := "cat"
[Definition: In a for
clause or
window
clause, when an expression is preceded by the
keyword in
, the value of that expression is called a
binding sequence.] The for
and
window
clauses iterate over their binding sequences,
producing multiple bindings for one or more variables. Details on
how binding sequences are used in for
and
window
clauses are described in the following
sections.
| [44] | ForClause |
::= | "for" ForBinding
("," ForBinding)* |
| [45] | ForBinding |
::= | "$" VarName TypeDeclaration? AllowingEmpty? PositionalVar? "in" ExprSingle |
| [167] | TypeDeclaration |
::= | "as" SequenceType |
| [46] | AllowingEmpty |
::= | "allowing" "empty" |
| [47] | PositionalVar |
::= | "at" "$" VarName |
A for
clause is used for iteration. Each variable
in a for
clause iterates over a sequence and is bound
in turn to each item in the sequence.
If a for
clause contains multiple variables, it is
semantically equivalent to multiple for
clauses, each
containing one of the variables in the original for
clause.
Example:
The clause
for $x in $expr1, $y in $expr2
is semantically equivalent to:
for $x in $expr1 for $y in $expr2
In the remainder of this section, we define the semantics of a
for
clause containing a single variable and an
associated expression (following the keyword in
) whose
value is called the binding sequence for that variable.
If a single-variable for
clause is the initial
clause in a FLWOR expression, it iterates over its binding
sequence, binding the variable to each item in turn. The
resulting sequence of variable bindings becomes the initial tuple
stream that serves as input to the next clause of the FLWOR
expression. If ordering mode is ordered
, the
order of tuples in the tuple stream preserves the order of the
binding
sequence; otherwise the order of the tuple stream is implementation-dependent.
If the binding sequence contains no items, the
output tuple stream depends on whether allowing empty
is specified. If allowing empty
is specified, the
output tuple stream consists of one tuple in which the variable is
bound to an empty sequence. If allowing empty
is not
specified, the output tuple stream consists of zero tuples.
The following examples illustrates tuple streams that are
generated by initial for
clauses:
Initial clause:
for $x in (100, 200, 300)
or (equivalently):
for $x allowing empty in (100, 200, 300)
Output tuple stream:
($x = 100) ($x = 200) ($x = 300)
Initial clause:
for $x in ()
Output tuple stream contains no tuples.
Initial clause:
for $x allowing empty in ()
Output tuple stream:
($x = ())
[Definition: A positional
variable is a variable that is preceded by the keyword
at
.] A positional variable may be associated with a
variable that is bound in a for
clause. In this case,
as the main variable iterates over the items in its binding
sequence, the positional variable iterates over the integers
that represent the ordinal numbers of these items in the binding
sequence, starting with one. Each tuple in the output tuple
stream contains bindings for both the main variable and the
positional variable. If the binding sequence is empty and
allowing empty
is specified, the positional variable
in the output tuple is bound to the integer zero. Positional
variables always have the implied type xs:integer
. The
expanded
QName of a positional variable must be distinct from the
expanded
QName of the main variable with which it is associated
[err:XQST0089].
The following examples illustrate how a positional variable would have affected the results of the previous examples that generated tuples:
Initial clause:
for $x at $i in (100, 200, 300)
Output tuple stream:
($x = 100, $i = 1) ($x = 200, $i = 2) ($x = 300, $i = 3)
Initial clause:
for $x allowing empty at $i in ()
Output tuple stream:
($x = (), $i = 0)
If a single-variable for
clause is an intermediate
clause in a FLWOR expression, its binding sequence is evaluated for each
input tuple, given the bindings in that input tuple. Each input
tuple generates zero or more tuples in the output tuple stream.
Each of these output tuples consists of the original variable
bindings of the input tuple plus a binding of the new variable to
one of the items in its binding sequence.
Note:
Although the binding sequence is conceptually evaluated independently for each input tuple, an optimized implementation may sometimes be able to avoid re-evaluating the binding sequence if it can show that the variables that the binding sequence depends on have the same values as in a previous evaluation.
For a given input tuple, if the binding sequence for the new
variable in the for
clause contains no items, the
result depends on whether allowing empty
is specified.
If allowing empty
is specified, the input tuple
generates one output tuple, with the original variable bindings
plus a binding of the new variable to an empty sequence. If
allowing empty
is not specified, the input tuple
generates zero output tuples (it is not represented in the output
tuple stream.)
If the new variable introduced by a for
clause has
an associated positional variable, the output
tuples generated by the for
clause also contain
bindings for the positional variable. In this case, as
the new variable is bound to each item in its binding
sequence, the positional variable is bound to the
ordinal position of that item within the binding
sequence, starting with one. Note that, since the positional
variable represents a position within a binding
sequence, the output tuples corresponding to each input tuple
are independently numbered, starting with one. For a given input
tuple, if the binding sequence is empty and
allowing empty
is specified, the positional
variable in the output tuple is bound to the integer zero.
If ordering
mode is ordered
, the tuples in the output tuple
stream are ordered primarily by the order of the input tuples from
which they are derived, and secondarily by the order of the
binding
sequence for the new variable; otherwise the order of the
output tuple stream is implementation-dependent.
The following examples illustrates the effects of intermediate
for
clauses:
Input tuple stream:
($x = 1) ($x = 2) ($x = 3) ($x = 4)
Intermediate for
clause:
for $y in ($x to 3)
Output tuple stream (assuming ordering mode is ordered
):
($x = 1, $y = 1) ($x = 1, $y = 2) ($x = 1, $y = 3) ($x = 2, $y = 2) ($x = 2, $y = 3) ($x = 3, $y = 3)
Note:
In this example, there is no output tuple that corresponds to
the input tuple ($x = 4)
because, when the
for
clause is evaluated with the bindings in this
input tuple, the resulting binding sequence for $y
is
empty.
This example shows how the previous example would have been affected by a positional variable (assuming the same input tuple stream):
for $y at $j in ($x to 3)
Output tuple stream (assuming ordering mode is ordered
):
($x = 1, $y = 1, $j = 1) ($x = 1, $y = 2, $j = 2) ($x = 1, $y = 3, $j = 3) ($x = 2, $y = 2, $j = 1) ($x = 2, $y = 3, $j = 2) ($x = 3, $y = 3, $j = 1)
This example shows how the previous example would have been
affected by allowing empty
. Note that allowing
empty
causes the input tuple ($x = 4)
to be
represented in the output tuple stream, even though the binding sequence
for $y
contains no items for this input tuple. This
example illustrates that allowing empty
in a
for
clause serves a purpose similar to that of an
"outer join" in a relational database query. (Assume the same input
tuple stream as in the previous example.)
for $y allowing empty at $j in ($x to 3)
Output tuple stream (assuming ordering mode is ordered
):
($x = 1, $y = 1, $j = 1) ($x = 1, $y = 2, $j = 2) ($x = 1, $y = 3, $j = 3) ($x = 2, $y = 2, $j = 1) ($x = 2, $y = 3, $j = 2) ($x = 3, $y = 3, $j = 1) ($x = 4, $y = (), $j = 0)
This example shows how a for
clause that binds two
variables is semantically equivalent to two for
clauses that bind one variable each. We assume that this
for
clause occurs at the beginning of a FLWOR
expression. It is equivalent to an initial single-variable
for
clause that provides an input tuple stream to an
intermediate single-variable for
clause.
for $x in (1, 2, 3, 4), $y in ($x to 3)
Output tuple stream (assuming ordering mode is ordered
):
($x = 1, $y = 1) ($x = 1, $y = 2) ($x = 1, $y = 3) ($x = 2, $y = 2) ($x = 2, $y = 3) ($x = 3, $y = 3)
In the above examples, if ordering mode had been
unordered
, the output tuple streams would have
consisted of the same tuples, with the same values for the
positional variables, but the
ordering of the tuples would have been implementation-dependent.
A for
clause may contain one or more type
declarations, identified by the keyword as
. The
semantics of type declarations are defined in
3.10.1 Variable
Bindings.
| [48] | LetClause |
::= | "let" LetBinding
("," LetBinding)* |
| [49] | LetBinding |
::= | "$" VarName TypeDeclaration? ":=" ExprSingle |
| [167] | TypeDeclaration |
::= | "as" SequenceType |
The purpose of a let
clause is to bind values to
one or more variables. Each variable is bound to the result of
evaluating an expression.
If a let
clause contains multiple variables, it is
semantically equivalent to multiple let
clauses, each
containing a single variable. For example, the clause
let $x := $expr1, $y := $expr2
is semantically equivalent to the following sequence of clauses:
let $x := $expr1 let $y := $expr2
In the remainder of this section, we define the semantics of a
let
clause containing a single variable V and
an associated expression E.
If a single-variable let
clause is the initial
clause in a FLWOR expression, it simply binds the variable
V to the result of the expression E. The result
of the let
clause is a tuple stream consisting of one
tuple with a single binding that binds V to the result of
E. This tuple stream serves as input to the next clause in
the FLWOR expression.
If a single-variable let
clause is an intermediate
clause in a FLWOR expression, it adds a new binding for variable
V to each tuple in the input tuple stream. For each input
tuple, the value bound to V is the result of evaluating
expression E, given the bindings that are already present
in that input tuple. The resulting tuples become the output tuple
stream of the let
clause.
The number of tuples in the output tuple stream of an
intermediate let
clause is the same as the number of
tuples in the input tuple stream. The number of bindings in the
output tuples is one more than the number of bindings in the input
tuples, unless the input tuples already contain bindings for
V; in this case, the new binding for V occludes
(replaces) the earlier binding for V, and the number of
bindings is unchanged.
A let
clause may contain one or more type
declarations, identified by the keyword as
. The
semantics of type declarations are defined in 3.10.1 Variable Bindings.
The following code fragment illustrates how a for
clause and a let
clause can be used together. The
for
clause produces an initial tuple stream containing
a binding for variable $d
to each department number
found in a given input document. The let
clause adds
an additional binding to each tuple, binding variable
$e
to a sequence of employees whose department number
matches the value of $d
in that tuple.
for $d in fn:doc("depts.xml")/depts/deptno let $e := fn:doc("emps.xml")/emps/emp[deptno eq $d]
| [50] | WindowClause |
::= | "for" (TumblingWindowClause |
SlidingWindowClause) |
| [51] | TumblingWindowClause |
::= | "tumbling" "window" "$" VarName TypeDeclaration? "in" ExprSingle WindowStartCondition
WindowEndCondition? |
| [52] | SlidingWindowClause |
::= | "sliding" "window" "$" VarName TypeDeclaration? "in" ExprSingle WindowStartCondition
WindowEndCondition |
| [53] | WindowStartCondition |
::= | "start" WindowVars
"when" ExprSingle |
| [54] | WindowEndCondition |
::= | "only"? "end" WindowVars "when" ExprSingle |
| [55] | WindowVars |
::= | ("$" CurrentItem)? PositionalVar? ("previous" "$"
PreviousItem)? ("next" "$"
NextItem)? |
| [56] | CurrentItem |
::= | EQName |
| [47] | PositionalVar |
::= | "at" "$" VarName |
| [57] | PreviousItem |
::= | EQName |
| [58] | NextItem |
::= | EQName |
Like a for
clause, a window
clause
iterates over its binding sequence and generates a
sequence of tuples. In the case of a window
clause,
each tuple represents a window. [Definition: A window is a sequence of
consecutive items drawn from the binding sequence.] Each window is
represented by at least one and at most nine bound variables. The
variables have user-specified names, but their roles are as
follows:
Window-variable: Bound to the sequence of items from the binding sequence that comprise the window.
Start-item: (Optional) Bound to the first item in the window.
Start-item-position: (Optional) Bound to the ordinal
position of the first window item in the binding
sequence. Start-item-position is a positional
variable; hence, its type is xs:integer
Start-previous-item: (Optional) Bound to the item in the binding sequence that precedes the first item in the window (empty sequence if none).
Start-next-item: (Optional) Bound to the item in the binding sequence that follows the first item in the window (empty sequence if none).
End-item: (Optional) Bound to the last item in the window.
End-item-position: (Optional) Bound to the ordinal
position of the last window item in the binding sequence.
End-item-position is a positional variable; hence, its
type is xs:integer
End-previous-item: (Optional) Bound to the item in the binding sequence that precedes the last item in the window (empty sequence if none).
End-next-item: (Optional) Bound to the item in the binding sequence that follows the last item in the window (empty sequence if none).
All variables in a window
clause must have distinct
names; otherwise a static error is raised [err:XQST0103].
The following is an example of a window
clause that
binds nine variables to the roles listed above. In this example,
the variables are named $w
, $s
,
$spos
, $sprev
, $snext
,
$e
, $epos
, $eprev
, and
$enext
respectively. A window
clause
always binds the window variable, but typically binds only a subset
of the other variables.
for tumbling window $w in (2, 4, 6, 8, 10) start $s at $spos previous $sprev next $snext when true() end $e at $epos previous $eprev next $enext when true()
Windows are created by iterating over the items in the binding
sequence, in order, identifying the start item and the end item
of each window by evaluating the WindowStartCondition and
the WindowEndCondition. Each of
these conditions is satisfied if the effective boolean
value of the expression following the when
keyword
is true
. The start item of the window is an item that
satisfies the WindowStartCondition (see
<IP_ADDRESS> Tumbling Windows
and <IP_ADDRESS> Sliding
Windows for a more complete explanation.) The end item of
the window is the first item in the binding sequence, beginning with
the start item, that satisfies the WindowEndCondition (again,
see <IP_ADDRESS> Tumbling
Windows and <IP_ADDRESS>
Sliding Windows for more details.) Each window contains its
start item, its end item, and all items that occur between them in
the binding
sequence. If the end item is the start item, then the window
contains only one item. If a start item is identified, but no
following item in the binding sequence satisfies the WindowEndCondition, then the
only
keyword determines whether a window is generated:
if only end
is specified, then no window is generated;
otherwise, the end item is set to the last item in the binding sequence
and a window is generated.
In the above example, the WindowStartCondition and
WindowEndCondition
are both true
, which causes each item in
the binding
sequence to be in a separate window. Typically, the WindowStartCondition and
WindowEndCondition
are expressed in terms of bound variables. For example, the
following WindowStartCondition might
be used to start a new window for every item in the binding sequence
that is larger than both the previous item and the following
item:
start $s previous $sprev next $snext when $s > $sprev and $s > $snext
The scoping rules for the variables bound by a
window
clause are as follows:
In the when
-expression of the WindowStartCondition, the
following variables (identified here by their roles) are in scope
(if bound): start-item, start-item-position,
start-previous-item, start-next-item.
In the when
-expression of the WindowEndCondition, the
following variables (identified here by their roles) are in scope
(if bound): start-item, start-item-position,
start-previous-item, start-next-item, end-item, end-item-position,
end-previous-item, end-next-item.
In the clauses of the FLWOR expression that follow the
window
clause, all nine of the variables bound by the
window
clause (including window-variable) are
in scope (if bound).
In a window
clause, the keyword
tumbling
or sliding
determines the way in
which the starting item of each window is identified, as explained
in the following sections.
If the window type is tumbling
, then windows never
overlap. The search for the start of the first window begins at the
beginning of the binding sequence. After each window is
generated, the search for the start of the next window begins with
the item in the binding sequence that occurs after the
ending item of the last generated window. Thus, no item that occurs
in one window can occur in another window drawn from the same
binding
sequence (unless the sequence contains the same item more
than once). In a tumbling window clause, the
end
clause is optional; if it is omitted, the
start
clause is applied to identify all potential
starting items in the binding sequence, and a window is
constructed for each starting item, including all items from that
starting item up to the item before the next window's starting
item, or the end of the binding sequence, whichever comes
first.
The following examples illustrate the use of tumbling windows.
Show non-overlapping windows of three items.
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14) start at $s when fn:true() only end at $e when $e - $s eq 2 return <window>{ $w }</window>
Result of the above query:
<window>2 4 6</window> <window>8 10 12</window>
Show averages of non-overlapping three-item windows.
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14) start at $s when fn:true() only end at $e when $e - $s eq 2 return avg($w)
Result of the above query:
4 10
Show first and last items in each window of three items.
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14) start $first at $s when fn:true() only end $last at $e when $e - $s eq 2 return <window>{ $first, $last }</window>
Result of the above query:
<window>2 6</window> <window>8 12</window>
Show non-overlapping windows of up to three items (illustrates
end
clause without the only
keyword).
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14) start at $s when fn:true() end at $e when $e - $s eq 2 return <window>{ $w }</window>
Result of the above query:
<window>2 4 6</window> <window>8 10 12</window> <window>14</window>
Show non-overlapping windows of up to three items (illustrates
use of start
without explicit end
).
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14) start at $s when $s mod 3 = 1 return <window>{ $w }</window>
Result of the above query:
<window>2 4 6</window> <window>8 10 12</window> <window>14</window>
Show non-overlapping sequences starting with a number divisible by 3.
for tumbling window $w in (2, 4, 6, 8, 10, 12, 14) start $first when $first mod 3 = 0 return <window>{ $w }</window>
Result of the above query:
<window>6 8 10</window> <window>12 14</window>
If the window type is sliding window
, then windows
may overlap. Every item in the binding sequence that satisfies the
WindowStartCondition is
the starting item of a new window. Thus, a given item may be found
in multiple windows drawn from the same binding sequence.
The following examples illustrate the use of sliding windows.
Show windows of three items.
for sliding window $w in (2, 4, 6, 8, 10, 12, 14) start at $s when fn:true() only end at $e when $e - $s eq 2 return <window>{ $w }</window>
Result of the above query:
<window>2 4 6</window> <window>4 6 8</window> <window>6 8 10</window> <window>8 10 12</window> <window>10 12 14</window>
Show moving averages of three items.
for sliding window $w in (2, 4, 6, 8, 10, 12, 14) start at $s when fn:true() only end at $e when $e - $s eq 2 return avg($w)
Result of the above query:
4 6 8 10 12
Show overlapping windows of up to three items (illustrates
end
clause without the only
keyword).
for sliding window $w in (2, 4, 6, 8, 10, 12, 14) start at $s when fn:true() end at $e when $e - $s eq 2 return <window>{ $w }</window>
Result of the above query:
<window>2 4 6</window> <window>4 6 8</window> <window>6 8 10</window> <window>8 10 12</window> <window>10 12 14</window> <window>12 14</window> <window>14</window>
The effects of a window
clause on the tuple stream
are similar to the effects of a for
clause. As
described in 3.10.4 Window Clause,
a window
clause generates zero or more windows, each
of which is represented by at least one and at most nine bound
variables.
If the window
clause is the initial clause in a
FLWOR expression, the bound variables that describe each window
become an output tuple. These tuples form the initial tuple stream
that serves as input to the next clause of the FLWOR expression. If
ordering mode
is ordered
, the order of tuples in the tuple stream is
the order in which their start items appear in the binding
sequence; otherwise the order of the tuple stream is implementation-dependent. The
cardinality of the tuple stream is equal to the number of
windows.
If a window
clause is an intermediate clause in a
FLWOR expression, each input tuple generates zero or more output
tuples, each consisting of the original bound variables of the
input tuple plus the new bound variables that represent one of the
generated windows. For each tuple T in the input tuple
stream, the output tuple stream will contain NT
tuples, where NT is the number of windows
generated by the window
clause, given the bindings in
the input tuple T. Input tuples for which no windows are
generated are not represented in the output tuple stream. If
ordering mode
is ordered
, the order of tuples in the output stream
is determined primarily by the order of the input tuples from which
they were derived, and secondarily by the order in which their
start items appear in the binding sequence. If ordering mode is
unordered
, the order of tuples in the output stream is
implementation-dependent.
The following example illustrates a window
clause
that is the initial clause in a FLWOR expression. The example is
based on input data that consists of a sequence of closing stock
prices for a specific company. For this example we assume the
following input data (assume that the price
elements
have a validated type of xs:decimal
):
<stock> <closing> <date>2008-01-01</date> <price>105</price> </closing> <closing> <date>2008-01-02</date> <price>101</price> </closing> <closing> <date>2008-01-03</date> <price>102</price> </closing> <closing> <date>2008-01-04</date> <price>103</price> </closing> <closing> <date>2008-01-05</date> <price>102</price> </closing> <closing> <date>2008-01-06</date> <price>104</price> </closing> </stock>
A user wishes to find "run-ups," which are defined as sequences of dates that begin with a "low" and end with a "high" price (that is, the stock price begins to rise on the first day of the run-up, and continues to rise or remain even through the last day of the run-up.) The following query uses a tumbling window to find run-ups in the input data:
for tumbling window $w in //closing start $first next $second when $first/price < $second/price end $last next $beyond when $last/price > $beyond/price return <run-up> <start-date>{fn:data($first/date)}</start-date> <start-price>{fn:data($first/price)}</start-price> <end-date>{fn:data($last/date)}</end-date> <end-price>{fn:data($last/price)}</end-price> </run-up>
For our sample input data, this tumbling window
clause generates a tuple stream consisting of two tuples, each
representing a window and containing five bound variables named
$w
, $first
, $second
,
$last
, and $beyond
. The
return
clause is evaluated for each of these tuples,
generating the following query result:
<run-up> <start-date>2008-01-02</start-date> <start-price>101</start-price> <end-date>2008-01-04</end-date> <end-price>103</end-price> </run-up> <run-up> <start-date>2008-01-05</start-date> <start-price>102</start-price> <end-date>2008-01-06</end-date> <end-price>104</end-price> </run-up>
The following example illustrates a window
clause
that is an intermediate clause in a FLWOR expression. In this
example, the input data contains closing stock prices for several
different companies, each identified by a three-letter symbol. We
assume the following input data (again assuming that the type of
the price
element is xs:decimal
):
<stocks> <closing> <symbol>ABC</symbol> <date>2008-01-01</date> <price>105</price> </closing> <closing> <symbol>DEF</symbol> <date>2008-01-01</date> <price>057</price> </closing> <closing> <symbol>ABC</symbol> <date>2008-01-02</date> <price>101</price> </closing> <closing> <symbol>DEF</symbol> <date>2008-01-02</date> <price>054</price> </closing> <closing> <symbol>ABC</symbol> <date>2008-01-03</date> <price>102</price> </closing> <closing> <symbol>DEF</symbol> <date>2008-01-03</date> <price>056</price> </closing> <closing> <symbol>ABC</symbol> <date>2008-01-04</date> <price>103</price> </closing> <closing> <symbol>DEF</symbol> <date>2008-01-04</date> <price>052</price> </closing> <closing> <symbol>ABC</symbol> <date>2008-01-05</date> <price>101</price> </closing> <closing> <symbol>DEF</symbol> <date>2008-01-05</date> <price>055</price> </closing> <closing> <symbol>ABC</symbol> <date>2008-01-06</date> <price>104</price> </closing> <closing> <symbol>DEF</symbol> <date>2008-01-06</date> <price>059</price> </closing> </stocks>
As in the previous example, we want to find "run-ups," which are
defined as sequences of dates that begin with a "low" and end with
a "high" price for a specific company. In this example, however,
the input data consists of stock prices for multiple companies.
Therefore it is necessary to isolate the stock prices of each
company before forming windows. This can be accomplished by an
initial for
and let
clause, followed by a
window
clause, as follows:
for $symbol in fn:distinct-values(//symbol) let $closings := //closing[symbol = $symbol] for tumbling window $w in $closings start $first next $second when $first/price < $second/price end $last next $beyond when $last/price > $beyond/price return <run-up symbol="{$symbol}"> <start-date>{fn:data($first/date)}</start-date> <start-price>{fn:data($first/price)}</start-price> <end-date>{fn:data($last/date)}</end-date> <end-price>{fn:data($last/price)}</end-price> </run-up>
Note:
In the above example, the for
and let
clauses could be rewritten as follows:
for $closings in //closing let $symbol := $closings/symbol group by $symbol
The group by
clause is described in 3.10.7 Group By Clause.
The for
and let
clauses in this query
generate an initial tuple stream consisting of two tuples. In the
first tuple, $symbol
is bound to "ABC" and
$closings
is bound to the sequence of
closing
elements for company ABC. In the second tuple,
$symbol
is bound to "DEF" and $closings
is bound to the sequence of closing
elements for
company DEF.
The window
clause operates on this initial tuple
stream, generating two windows for the first tuple and two windows
for the second tuple. The result is a tuple stream consisting of
four tuples, each with the following bound variables:
$symbol
, $closings
, $w
,
$first
, $second
, $last
, and
$beyond
. The return
clause is then
evaluated for each of these tuples, generating the following query
result:
<run-up symbol="ABC"> <start-date>2008-01-02</start-date> <start-price>101</start-price> <end-date>2008-01-04</end-date> <end-price>103</end-price> </run-up> <run-up symbol="ABC"> <start-date>2008-01-05</start-date> <start-price>101</start-price> <end-date>2008-01-06</end-date> <end-price>104</end-price> </run-up> <run-up symbol="DEF"> <start-date>2008-01-02</start-date> <start-price>054</start-price> <end-date>2008-01-03</end-date> <end-price>056</end-price> </run-up> <run-up symbol="DEF"> <start-date>2008-01-04</start-date> <start-price>052</start-price> <end-date>2008-01-06</end-date> <end-price>059</end-price> </run-up>
| [60] | WhereClause |
::= | "where" ExprSingle |
A where
clause serves as a filter for the tuples in
its input tuple stream. The expression in the where
clause, called the where-expression, is evaluated once for
each of these tuples. If the effective boolean value of the where-expression
is true
, the tuple is retained in the output tuple
stream; otherwise the tuple is discarded.
Examples:
This example illustrates the effect of a where
clause on a tuple stream:
Input tuple stream:
($a = 5, $b = 11) ($a = 91, $b = 42) ($a = 17, $b = 30) ($a = 85, $b = 63)
where
clause:
where $a > $b
Output tuple stream:
($a = 91, $b = 42) ($a = 85, $b = 63)
The following query illustrates how a where
clause
might be used with a positional variable to perform
sampling on an input sequence. The query returns one value out of
each one hundred input values.
for $x at $i in $inputvalues
where $i mod 100 = 0
return $x
| [59] | CountClause |
::= | "count" "$" VarName |
The purpose of a count
clause is to enhance the
tuple stream with a new variable that is bound, in each tuple, to
the ordinal position of that tuple in the tuple stream. The name of
the new variable is specified in the count
clause.
The output tuple stream of a count
clause is the
same as its input tuple stream, with each tuple enhanced by one
additional variable that is bound to the ordinal position of that
tuple in the tuple stream. However, if the name of the new variable
is the same as the name of an existing variable in the input tuple
stream, the new variable occludes (replaces) the existing variable
of the same name, and the number of bound variables in each tuple
is unchanged.
The following examples illustrate uses of the count
clause:
This example illustrates the effect of a count
clause on an input tuple stream:
Input tuple stream:
($name = "Bob", $age = 21) ($name = "Carol", $age = 19) ($name = "Ted", $age = 20) ($name = "Alice", $age = 22)
count
clause:
count $counter
Output tuple stream:
($name = "Bob", $age = 21, $counter = 1) ($name = "Carol", $age = 19, $counter = 2) ($name = "Ted", $age = 20, $counter = 3) ($name = "Alice", $age = 22, $counter = 4)
This example illustrates how a counter might be used to filter
the result of a query. The query ranks products in order by
decreasing sales, and returns the three products with the highest
sales. Assume that the variable $products
is bound to
a sequence of product
elements, each of which has
name
and sales
child-elements.
for $p in $products order by $p/sales descending count $rank where $rank <= 3 return <product rank="{$rank}"> {$p/name, $p/sales} </product>
The result of this query has the following structure:
<product rank="1"> <name>Toaster</name> <sales>968</sales> </product> <product rank="2"> <name>Blender</name> <sales>520</sales> </product> <product rank="3"> <name>Can Opener</name> <sales>475</sales> </product>
| [61] | GroupByClause |
::= | "group" "by" GroupingSpecList |
| [62] | GroupingSpecList |
::= | GroupingSpec
("," GroupingSpec)* |
| [63] | GroupingSpec |
::= | GroupingVariable (TypeDeclaration? ":=" ExprSingle)? ("collation" URILiteral)? |
| [64] | GroupingVariable |
::= | "$" VarName |
A group by
clause generates an output tuple stream
in which each tuple represents a group of tuples from the input
tuple stream that have equivalent grouping keys. We
will refer to the tuples in the input tuple stream as
pre-grouping tuples, and the tuples in the output tuple
stream as post-grouping tuples.
The group by
clause assigns each pre-grouping tuple
to a group, and generates one post-grouping tuple for each group.
In the post-grouping tuple for a group, each grouping key is
represented by a variable that was specified in a GroupingSpec, and every variable
that appears in the pre-grouping tuples that were assigned to that
group is represented by a variable of the same name, bound to a
sequence of all values bound to the variable in any of these
pre-grouping tuples. Subsequent clauses in the FLWOR
expression see only the variable bindings in the post-grouping
tuples; they no longer have access to the variable bindings in the
pre-grouping tuples. The number of post-grouping tuples is
less than or equal to the number of pre-grouping tuples.
A group by
clause contains one or more grouping specifications, as shown
in the grammar. [Definition:
Each grouping specification specifies one grouping variable, which
refers to variable bindings in the pre-grouping tuples. The values
of the grouping variables are used to assign pre-grouping tuples to
groups.] Each grouping specification may optionally provide an
expression to which its grouping variable is bound. If no
expression is provided, the grouping variable name must be equal
(by the eq
operator on expanded QNames) to the name of a variable
in the input tuple stream, and it refers to that variable;
otherwise a static
error is raised [err:XQST0094]. For each grouping specification
that contains a binding expression, a let
binding is
created in the pre-grouping tuples, and the grouping variable
refers to that let
binding. For example, the
clause:
group by $g1, $g2 := $expr1, $g3 := $expr2 collation "Spanish"
is semantically equivalent to the following sequence of clauses:
let $g2 := $expr1 let $g3 := $expr2 group by $g1, $g2, $g3 collation "Spanish"
The process of group formation proceeds as follows:
[Definition: The atomized value of a grouping variable is called a grouping key.] For each pre-grouping tuple, the grouping keys are created by atomizing the values of the grouping variables (in the post-grouping tuples, each grouping variable is set to the value of the corresponding grouping key, as discussed below). If the value of any grouping variable consists of more than one item, a type error is raised [err:XPTY0004]. If a type declaration is present and the resulting atomized value is not an instance of the specified type, a type error is raised [err:XPTY0004].
The input tuple stream is partitioned into groups of tuples
whose grouping keys are equivalent. [Definition: Two tuples
T1 and T2 have equivalent grouping
keys if and only if, for each grouping variable GV,
the atomized value of GV in T1 is deep-equal
to the atomized value of GV in T2, as defined
by applying the function fn:deep-equal
using the
appropriate collation.] If these values are of different numeric
types, and differ from each other by small amounts, then the
deep-equal relationship is not transitive, because of rounding
effects occurring during type promotion. When comparing three
values A
, B
, and C
such that
A eq B
, B eq C
, but A ne C
,
then the number of items in the result of the function (as well as
the choice of which items are returned) is
subject only to the constraints that (a) no two items in the result
sequence compare equal to each other, and (b) every input item that
does not appear in the result sequence compares equal to some item
that does appear in the result sequence. See Section
14.2.1 fn:distinct-values FO30 for
further discussion of this issue in a different context.
Note:
The atomized grouping key will always be either an empty
sequence or a single atomic value. Defining equivalence by
reference to the fn:deep-equal
function ensures that
the empty sequence is equivalent only to the empty sequence, that
NaN
is equivalent to NaN
, that
untypedAtomic values are compared as strings, and that values for
which the eq
operator is not defined are considered
non-equivalent.
The appropriate collation for comparing two grouping keys is the collation specified in the pertinent GroupingSpec if present, or the default collation from the static context otherwise. If the collation is specified by a relative URI, that relative URI is resolved to an absolute URI using the Static Base URI. If the specified collation is not found in statically known collations, a static error is raised [err:XQST0076].
Each group of tuples produced by the above process results in one post-grouping tuple. The pre-grouping tuples from which the group is derived have equivalent grouping keys, but these keys are not necessarily identical (for example, the strings "Frog" and "frog" might be equivalent according to the collation in use.) In the post-grouping tuple, each grouping variable is bound to the value of the corresponding grouping key.
In the post-grouping tuple generated for a given group, each
non-grouping variable is bound to a sequence containing the
concatenated values of that variable in all the pre-grouping tuples
that were assigned to that group. If ordering mode is ordered
, the
values derived from individual tuples are concatenated in a way
that preserves the order of the pre-grouping tuple stream;
otherwise the ordering of these values is implementation-dependent.
Note:
This behavior may be surprising to SQL programmers, since SQL reduces the equivalent of a non-grouping variable to one representative value. Consider the following query:
let $x := 64000 for $c in //customer where $c/salary > $x group by $d := $c/department return <department name="{$d}"> Number of employees earning more than ${$x} is {count($c)} </department>
If there are three qualifying customers in the sales department this evaluates to:
<department name="sales"> Number of employees earning more than $64000 64000 64000 is 3 </department>
In XQuery, each group is a sequence of items that match the
group by criteria—in a tree-structured language like XQuery, this
is convenient, because further structures can be built based on the
items in this sequence. Because there are three items in the group,
$x
evaluates to a sequence of three items. To reduce
this to one item, use fn:distinct-values()
:
let $x := 64000 for $c in //customer let $d := $c/department where $c/salary > $x group by $d return <department name="{$d}"> Number of employees earning more than ${distinct-values($x)} is {count($c)} </department>
Note:
In general, the static type of a variable in a post-grouping tuple is different from the static type of the variable with the same name in the pre-grouping tuples.
The order in which tuples appear in the post-grouping tuple stream is implementation-dependent.
Note:
An order by
clause can be used to impose a
value-based ordering on the post-grouping tuple stream. Similarly,
if it is desired to impose a value-based ordering within a group
(i.e., on the sequence of items bound to a non-grouping variable),
this can be accomplished by a nested FLWOR expression that iterates
over these items and applies an order by
clause. In
some cases, a value-based ordering within groups can be
accomplished by applying an order by
clause on a
non-grouping variable before applying the group by
clause.
A group by
clause rebinds all the variables in the
input tuple stream. The scopes of these variables are not affected
by the group by
clause, but in post-grouping tuples
the values of the variables represent group properties rather than
properties of individual pre-grouping tuples.
Examples:
This example illustrates the effect of a group by
clause on a tuple stream.
Input tuple stream:
($storeno = <storeno>S101</storeno>, $itemno = <itemno>P78395</itemno>) ($storeno = <storeno>S102</storeno>, $itemno = <itemno>P94738</itemno>) ($storeno = <storeno>S101</storeno>, $itemno = <itemno>P41653</itemno>) ($storeno = <storeno>S102</storeno>, $itemno = <itemno>P70421</itemno>)
group by
clause:
group by $storeno
Output tuple stream:
($storeno = S101, $itemno = (<itemno>P78395</itemno>, <itemno>P41653<itemno>)) ($storeno = S102, $itemno = (<itemno>P94738</itemno>, <itemno>P70421</itemno>))
This example and the ones that follow are based on two separate
sequences of elements, named $sales
and
$products
. We assume that the variable
$sales
is bound to a sequence of elements with the
following structure:
<sales> <storeno>S101</storeno> <itemno>P78395</itemno> <qty>125</qty> </sales>
We also assume that the variable $products
is bound
to a sequence of elements with the following structure:
<product> <itemno>P78395</itemno> <price>25.00</price> <category>Men's Wear</category> </product>
The simplest kind of grouping query has a single grouping variable. The query in this example finds the total quantity of items sold by each store:
for $s in $sales let $storeno := $s/storeno group by $storeno return <store number="{$storeno}" total-qty="{sum($s/qty)}"/>
The result of this query is a sequence of elements with the following structure:
<store number="S101" total-qty="1550" /> <store number="S102" total-qty="2125" />
In a more realistic example, a user might be interested in the total revenue generated by each store for each product category. Revenue depends on both the quantity sold of various items and the price of each item. The following query joins the two input sequences and groups the resulting tuples by two grouping variables:
for $s in $sales, $p in $products[itemno = $s/itemno] let $revenue := $s/qty * $p/price group by $storeno := $s/storeno, $category := $p/category return
The result of this query is a sequence of elements with the following structure:

The result of the previous example was a "flat" list of elements. A user might prefer the query result to be presented in the form of a hierarchical report, grouped primarily by store (in order by store number) and secondarily by product category. Within each store, the user might want to see only those product categories whose total revenue exceeds $10,000, presented in descending order by their total revenue. This report is generated by the following query:
for $s1 in $sales let $storeno := $s1/storeno group by $storeno order by $storeno return <store storeno="{$storeno}"> {for $s2 in $s1, $p in $products[itemno = $s2/itemno] let $category := $p/category, $revenue := $s2/qty * $p/price group by $category let $group-revenue := sum($revenue) where $group-revenue > 10000 order by $group-revenue descending return <category name="{$category}" revenue="{$group-revenue}"/> } </store>
The result of this example query has the following structure:
<store storeno="S101"> <category name="Men's Wear" revenue="10185"/> </store> <store storeno="S102"> <category name="Jewelry" revenue="30750"/> <category name="Appliances" revenue="22650"/> </store>
The following example illustrates how to avoid a possible pitfall in writing grouping queries.
In each post-grouping tuple, all variables except for the
grouping variable are bound to sequences of items derived from all
the pre-grouping tuples from which the group was formed. For
instance, in the following query, $high-price
is bound
to a sequence of items in the post-grouping tuple.
let $high-price := 1000 for $p in $products[price > $high-price] let $category := $p/category group by $category return <category name="{$category}"> {fn:count($p)} products have price greater than {$high-price}. </category>
If three products in the "Men's Wear" category have prices greater than 1000, the result of this query might look (in part) like this:
<category name="Men's Wear"> 3 products have price greater than 1000 1000 1000. </category>
The repetition of "1000" in this query result is due to the fact
that $high-price
is not a grouping variable. One way to
avoid this repetition is to move the binding of
$high-price
to an outer-level FLWOR expression, as
follows:
let $high-price := 1000 return for $p in $products[price > $high-price] let $category := $p/category group by $category return <category name="{$category}"> {fn:count($p)} products have price greater than {$high-price}. </category>
The result of the revised query might contain the following element:
<category name="Men's Wear"> 3 products have price greater than 1000. </category>
| [65] | OrderByClause |
::= | (("order" "by") | ("stable" "order" "by")) OrderSpecList |
| [66] | OrderSpecList |
::= | OrderSpec (","
OrderSpec)* |
| [67] | OrderSpec |
::= | ExprSingle
OrderModifier |
| [68] | OrderModifier |
::= | ("ascending" | "descending")? ("empty" ("greatest" |
"least"))? ("collation" URILiteral)? |
The purpose of an order by
clause is to impose a
value-based ordering on the tuples in the tuple stream. The output
tuple stream of the order by
clause contains the same
tuples as its input tuple stream, but the tuples may be in a
different order.
An order by
clause contains one or more ordering
specifications, called orderspecs, as shown in the grammar.
For each tuple in the input tuple stream, the orderspecs are
evaluated, using the variable bindings in that tuple. The relative
order of two tuples is determined by comparing the values of their
orderspecs, working from left to right until a pair of unequal
values is encountered. If an orderspec specifies a collation, that collation is
used in comparing values of type xs:string
,
xs:anyURI
, or types derived from them (otherwise, the
default
collation is used in comparing values of these types). If an
orderspec specifies a collation by a relative URI, that relative
URI is resolved
to an absolute URI using the Static Base URI. If an
orderspec specifies a collation that is not found in statically known collations, an error
is raised [err:XQST0076].
The process of evaluating and comparing the orderspecs is based on the following rules:
Atomization is applied to the result of the expression in each orderspec. If the result of atomization is neither a single atomic value nor an empty sequence, a type error is raised [err:XPTY0004].
If the value of an orderspec has the dynamic type
xs:untypedAtomic
(such as character data in a
schemaless document), it is cast to the type
xs:string
.
Note:
Consistently treating untyped values as strings enables the sorting process to begin without complete knowledge of the types of all the values to be sorted.
All the non-empty orderspec values must be convertible to a
common type by subtype substitution and/or
type
promotion. The ordering is performed in the least common type
that has a gt
operator. If two or more non-empty
orderspec values are not convertible to a common type that has a
gt
operator, a type error is raised [err:XPTY0004].
Example: The orderspec values include a value of type
hatsize
, which is derived from
xs:integer
, and a value of type shoesize
,
which is derived from xs:decimal
. The least common
type reachable by subtype substitution and type promotion is
xs:decimal
.
Example: The orderspec values include a value of type
xs:string
and a value of type xs:anyURI
.
The least common type reachable by subtype substitution and type
promotion is xs:string
.
For the purpose of determining their relative position in the ordering sequence, the greater-than relationship between two orderspec values W and V is defined as follows:
When the orderspec specifies empty least
, the
following rules are applied in order:
If V is an empty sequence and W is not an empty sequence, then W greater-than V is true.
If V is NaN
and W is neither
NaN
nor an empty sequence, then W
greater-than V is true.
If a specific collation C is specified, and V
and W are both of type xs:string
or are
convertible to xs:string
by subtype
substitution and/or type promotion, then:
If fn:compare(V, W, C)
is less than zero, then
W greater-than V is true; otherwise
W greater-than V is false.
If none of the above rules apply, then:
If W gt V
is true, then W
greater-than V is true; otherwise W
greater-than V is false.
When the orderspec specifies empty greatest
, the
following rules are applied in order:
If W is an empty sequence and V is not an empty sequence, then W greater-than V is true.
If W is NaN
and V is neither
NaN
nor an empty sequence, then W
greater-than V is true.
If a specific collation C is specified, and V
and W are both of type xs:string
or are
convertible to xs:string
by subtype
substitution and/or type promotion, then:
If fn:compare(V, W, C)
is less than zero, then
W greater-than V is true; otherwise
W greater-than V is false.
If none of the above rules apply, then:
If W gt V
is true, then W
greater-than V is true; otherwise W
greater-than V is false.
When the orderspec specifies neither empty least
nor empty greatest
, the default order for empty sequences in
the static
context determines whether the rules for empty
least
or empty greatest
are used.
If T1 and T2 are two tuples in the input tuple stream, and V1 and V2 are the first pair of values encountered when evaluating their orderspecs from left to right for which one value is greater-than the other (as defined above), then:
If V1 is greater-than V2: If the
orderspec specifies descending
, then T1
precedes T2 in the output tuple stream; otherwise,
T2 precedes T1 in the output tuple stream.
If V2 is greater-than V1: If the
orderspec specifies descending
, then T2
precedes T1 in the output tuple stream; otherwise,
T1 precedes T2 in the output tuple stream.
If neither V1 nor V2 is greater-than the other for any pair of orderspecs for tuples T1 and T2, the following rules apply.
If stable
is specified, the original order of
T1 and T2 is preserved in the output tuple
stream.
If stable
is not specified, the order of
T1 and T2 in the output tuple stream is implementation-dependent.
Note:
If two orderspecs return the special floating-point values
positive and negative zero, neither of these values is
greater-than the other, since +0.0 gt -0.0
and -0.0 gt +0.0
are both false
.
Examples:
This example illustrates the effect of an order by
clause on a tuple stream. The keyword stable
indicates
that, when two tuples have equal sort keys, their order in the
input tuple stream is preserved.
Input tuple stream:
($license = "PFQ519", $make = "Ford", $value = 16500) ($license = "HAJ865", $make = "Honda", $value = 22750) ($license = "NKV473", $make = "Ford", $value = 21650) ($license = "RCM922", $make = "Dodge", $value = 11400) ($license = "ZBX240", $make = "Ford", $value = 16500) ($license = "KLM030", $make = "Dodge", $value = () )
order by
clause:
stable order by $make, $value descending empty least
Output tuple stream:
($license = "RCM922", $make = "Dodge", $value = 11400) ($license = "KLM030", $make = "Dodge", $value = () ) ($license = "NKV473", $make = "Ford", $value = 21650) ($license = "PFQ519", $make = "Ford", $value = 16500) ($license = "ZBX240", $make = "Ford", $value = 16500) ($license = "HAJ865", $make = "Honda", $value = 22750)
The following example shows how an order by
clause
can be used to sort the result of a query, even if the sort key is
not included in the query result. This query returns employee names
in descending order by salary, without returning the actual
salaries:
for $e in $employees order by $e/salary descending return $e/name
Note:
Since the order by
clause in a FLWOR expression is
the only facility provided by XQuery for specifying a value
ordering, a FLWOR expression must be used in some queries where
iteration would not otherwise be necessary. For example, a list of
books with price less than 100 might be obtained by a simple
path
expression such as $books/book[price < 100]
.
But if these books are to be returned in alphabetic order by title,
the query must be expressed as follows:
for $b in $books/book[price < 100] order by $b/title return $b
| [69] | ReturnClause |
::= | "return" ExprSingle |
The return
clause is the final clause of a FLWOR
expression. The return
clause is evaluated once for
each tuple in its input tuple stream, using the variable bindings
in the respective tuples, in the order in which these tuples appear
in the input tuple stream. The results of these evaluations are
concatenated, as if by the comma operator, to form the result of the
FLWOR expression.
The following example illustrates a FLWOR expression containing
several clauses. The for
clause iterates over all the
departments in an input document named depts.xml
,
binding the variable $d
to each department in turn.
For each binding of $d
, the let
clause
binds variable $e
to all the employees in the given
department, selected from another input document named
emps.xml
(the relationship between employees and
departments is represented by matching their deptno
values). Each tuple in the resulting tuple stream contains a pair
of bindings for $d
and $e
($d
is bound to a department and $e
is
bound to a set of employees in that department). The
where
clause filters the tuple stream, retaining only
those tuples that represent departments having at least ten
employees. The order by
clause orders the surviving
tuples in descending order by the average salary of the employees
in the department. The return
clause constructs a new
big-dept
element for each surviving tuple, containing
the department number, headcount, and average salary.
for $d in fn:doc("depts.xml")//dept let $e := fn:doc("emps.xml")//emp[deptno eq $d/deptno] where fn:count($e) >= 10 order by fn:avg($e/salary) descending return <big-dept> { $d/deptno, <headcount>{fn:count($e)}</headcount>, <avgsal>{fn:avg($e/salary)}</avgsal> } </big-dept>
Notes:
The order in which items appear in the result of a FLWOR
expression depends on the ordering of the input tuple stream to the
return
clause, which in turn is influenced by
order by
clauses and by ordering mode. For example, consider the
following query, which is based on the same two input documents as
the previous example:
for $d in fn:doc("depts.xml")//dept order by $d/deptno for $e in fn:doc("emps.xml")//emp[deptno eq $d/deptno] return <assignment> {$d/deptno, $e/name} </assignment>
The result of this query is a sequence of
assignment
elements, each containing a
deptno
element and a name
element. The
sequence will be ordered primarily by the deptno
values because of the order by
clause. If ordering mode is
ordered
, subsequences of assignment
elements with equal deptno
values will be ordered by
the document order of their name
elements within the
emps.xml
document; otherwise the ordering of these
subsequences will be implementation-dependent.
Parentheses are helpful in return
clauses that
contain comma operators, since FLWOR expressions have a higher
precedence than the comma operator. For example, the following
query raises an error because after the comma, $j
is
no longer within the FLWOR expression, and is an undefined
variable:
let $i := 5, $j := 20 * $i return $i, $j
Parentheses can be used to bring $j
into the
return
clause of the FLWOR expression, as the
programmer probably intended:
let $i := 5, $j := 20 * $i return ($i, $j)
| [131] | OrderedExpr |
::= | "ordered" "{" Expr
"}" |
| [132] | UnorderedExpr |
::= | "unordered" "{" Expr
"}" |
The purpose of ordered
and unordered
expressions is to set the ordering mode in the static context to
ordered
or unordered
for a certain region
in a query. The specified ordering mode applies to the expression
nested inside the curly braces. For expressions where the ordering
of the result is not significant, a performance advantage may be
realized by setting the ordering mode to unordered
,
thereby granting the system flexibility to return the result in the
order that it finds most efficient.
Ordering
mode affects the behavior of path expressions that include a
"/
" or "//
" operator or an axis step; union
,
intersect
, and except
expressions; the
fn:id
, fn:element-with-id
,
and fn:idref
functions; and certain clauses within a
FLWOR expression. If ordering mode is ordered
, node
sequences returned by path expressions, union
,
intersect
, and except
expressions, and
the fn:id
and fn:idref
functions are in
document
order; otherwise the order of these return sequences is
implementation-dependent. The
effect of ordering mode on FLWOR expressions is described in
3.10.2 For Clause,
<IP_ADDRESS> Effects of
Window Clauses on the Tuple Stream, and 3.10.7 Group By Clause. Ordering mode has
no effect on duplicate elimination.
Note:
In a region of a query where ordering mode is
unordered
, the result of an expression is implementation-dependent if the
expression invokes certain functions that are affected by the
ordering of node sequences. These functions include
fn:position
, fn:last
,
fn:index-of
, fn:insert-before
,
fn:remove
, fn:reverse
, and
fn:subsequence
. The functions
fn:boolean
and fn:not
are implementation-dependent if
ordering mode is unordered
and the argument contains
at least one node and at least one atomic value (see 2.4.3 Effective Boolean Value). Also,
within a path
expression in an unordered region, numeric predicates are
nondeterministic. For example, in an ordered region, the path
expression (//a/b)[5]
will return the fifth qualifying
b
-element in document order. In an unordered region,
the same expression will return an implementation-dependent
qualifying b
-element.
Note:
The fn:id
and fn:idref
functions are
described in [XQuery and XPath
Functions and Operators 3.0] as returning their results in
document
order. Since ordering mode is a feature of XQuery, relaxation
of the ordering requirement for function results when ordering mode
is unordered
is a feature of XQuery rather than of the
functions themselves.
The use of an unordered
expression is illustrated
by the following example, which joins together two documents named
parts.xml
and suppliers.xml
. The example
returns the part numbers of red parts, paired with the supplier
numbers of suppliers who supply these parts. If an
unordered
expression were not used, the resulting list
of (part number, supplier number) pairs would be required to have
an ordering that is controlled primarily by the document order of
parts.xml
and secondarily by the document order of
suppliers.xml
. However, this might not be the most
efficient way to process the query if the ordering of the result is
not important. An XQuery implementation might be able to process
the query more efficiently by using an index to find the red parts,
or by using suppliers.xml
rather than
parts.xml
to control the primary ordering of the
result. The unordered
expression gives the query
evaluator freedom to make these kinds of optimizations.
unordered { for $p in fn:doc("parts.xml")/parts/part[color = "Red"], $s in fn:doc("suppliers.xml")/suppliers/supplier where $p/suppno = $s/suppno return <ps> { $p/partno, $s/suppno } </ps> }
In addition to ordered
and unordered
expressions, XQuery provides a function named
fn:unordered
that operates on any sequence of items
and returns the same sequence in an implementation-defined order. A
call to the fn:unordered
function may be thought of as
giving permission for the argument expression to be materialized in
whatever order the system finds most efficient. The
fn:unordered
function relaxes ordering only for the
sequence that is its immediate operand, whereas an
unordered
expression sets the ordering mode for its operand
expression and all nested expressions.
XQuery 3.0 supports a conditional expression based on the
keywords if
, then
, and
else
.
| [77] | IfExpr |
::= | "if" "(" Expr ")" "then"
ExprSingle "else" ExprSingle |
The expression following the if
keyword is called
the test expression, and the expressions following the
then
and else
keywords are called the
then-expression and else-expression,
respectively.
The first step in processing a conditional expression is to find the effective boolean value of the test expression, as defined in 2.4.3 Effective Boolean Value.
The value of a conditional expression is defined as follows: If
the effective boolean value of the test expression is
true
, the value of the then-expression is returned. If
the effective boolean value of the test expression is
false
, the value of the else-expression is
returned.
Conditional expressions have a special rule for propagating
dynamic
errors. If the effective value of the test expression is
true
, the conditional expression ignores (does not
raise) any dynamic errors encountered in the else-expression. In
this case, since the else-expression can have no observable effect,
it need not be evaluated. Similarly, if the effective value of the
test expression is false
, the conditional expression
ignores any dynamic errors encountered in the
then-expression, and the then-expression need not be evaluated.
Here are some examples of conditional expressions:
In this example, the test expression is a comparison expression:
if ($widget1/unit-cost < $widget2/unit-cost) then $widget1 else $widget2
In this example, the test expression tests for the existence of
an attribute named discounted
, independently of its
value:
if ($part/@discounted) then $part/wholesale else $part/retail
| [71] | SwitchExpr |
::= | "switch" "(" Expr ")"
SwitchCaseClause+
"default" "return" ExprSingle |
| [72] | SwitchCaseClause |
::= | ("case" SwitchCaseOperand)+ "return"
ExprSingle |
| [73] | SwitchCaseOperand |
::= | ExprSingle |
The switch expression chooses one of several expressions to evaluate based on the input value.
In a switch
expression, the switch
keyword is followed by an expression enclosed in parentheses,
called the switch operand expression. This is the expression
whose value is being compared. The remainder of the
switch
expression consists of one or more
case
clauses, with one or more case operand
expressions
each, and a default
clause.
The first step in evaluating a switch expression is to apply atomization to the value of the switch operand expression. If the result is a sequence of length greater than one, a type error is raised [err:XPTY0004].
The resulting value is matched against each SwitchCaseOperand in turn until a match is found or the list is exhausted. The matching is performed as follows:
The SwitchCaseOperand is evaluated.
The resulting value is atomized.
If the atomized sequence has length greater than one, a type error is raised [err:XPTY0004].
The atomized value of the switch operand expression is compared
with the atomized value of the SwitchCaseOperand using the
fn:deep-equal
function, with the default collation
from the static context.
[Definition: The effective case of a switch expression is the first case clause that matches, using the rules given above, or the default clause if no such case clause exists.] The value of the switch expression is the value of the return expression in the effective case.
Switch expressions have rules regarding the propagation of dynamic errors that take precedence over the general rules given in 2.3.4 Errors and Optimization. The return clauses of a switch expression must not raise any dynamic errors except in the effective case. Dynamic errors raised in the operand expressions of the switch or the case clauses are propagated; however, an implementation must not raise dynamic errors in the operand expressions of case clauses that occur after the effective case. An implementation is permitted to raise dynamic errors in the operand expressions of case clauses that occur before the effective case, but not required to do so.
The following example shows how a switch expression might be used:
switch ($animal) case "Cow" return "Moo" case "Cat" return "Meow" case "Duck" return "Quack" default return "What's that odd noise?"
Quantified expressions support existential and universal
quantification. The value of a quantified expression is always
true
or false
.
| [70] | QuantifiedExpr |
::= | ("some" | "every") "$" VarName TypeDeclaration? "in" ExprSingle ("," "$" VarName TypeDeclaration? "in" ExprSingle)* "satisfies" ExprSingle |
| [167] | TypeDeclaration |
::= | "as" SequenceType |
A quantified expression begins with a quantifier,
which is the keyword some
or every
,
followed by one or more in-clauses that are used to bind variables,
followed by the keyword satisfies
and a test
expression. Each in-clause associates a variable with an expression
that returns a sequence of items, called the binding sequence for
that variable. The in-clauses generate tuples of variable bindings,
including a tuple for each combination of items in the binding
sequences of the respective variables. Conceptually, the test
expression is evaluated for each tuple of variable bindings.
Results depend on the effective boolean value of the test expressions, as
defined in 2.4.3 Effective Boolean
Value. The value of the quantified expression is defined by
the following rules:
If the quantifier is some
, the quantified
expression is true
if at least one evaluation of the
test expression has the effective boolean value true
; otherwise
the quantified expression is false
. This rule implies
that, if the in-clauses generate zero binding tuples, the value of
the quantified expression is false
.
If the quantifier is every
, the quantified
expression is true
if every evaluation of the test
expression has the effective boolean value true
; otherwise
the quantified expression is false
. This rule implies
that, if the in-clauses generate zero binding tuples, the value of
the quantified expression is true
.
The scope of a variable bound in a quantified expression comprises all subexpressions of the quantified expression that appear after the variable binding. The scope does not include the expression to which the variable is bound.
Each variable bound in an in-clause of a quantified expression may have an optional type declaration. If the type of a value bound to the variable does not match the declared type according to the rules for SequenceType matching, a type error is raised [err:XPTY0004].
The order in which test expressions are evaluated for the
various binding tuples is implementation-dependent. If the
quantifier is some
, an implementation may return
true
as soon as it finds one binding tuple for which
the test expression has an effective boolean value of true
, and it
may raise a dynamic error as soon as it finds one
binding tuple for which the test expression raises an error.
Similarly, if the quantifier is every
, an
implementation may return false
as soon as it finds
one binding tuple for which the test expression has an effective boolean
value of false
, and it may raise a dynamic error as soon
as it finds one binding tuple for which the test expression raises
an error. As a result of these rules, the value of a quantified
expression is not deterministic in the presence of errors, as
illustrated in the examples below.
Here are some examples of quantified expressions:
This expression is true
if every part
element has a discounted
attribute (regardless of the
values of these attributes):
every $part in /parts/part satisfies $part/@discounted
This expression is true
if at least one
employee
element satisfies the given comparison
expression:
some $emp in /emps/employee satisfies ($emp/bonus > 0.25 * $emp/salary)
In the following examples, each quantified expression evaluates
its test expression over nine tuples of variable bindings, formed
from the Cartesian product of the sequences (1, 2, 3)
and (2, 3, 4)
. The expression beginning with
some
evaluates to true
, and the
expression beginning with every
evaluates to
false
.
some $x in (1, 2, 3), $y in (2, 3, 4) satisfies $x + $y = 4
every $x in (1, 2, 3), $y in (2, 3, 4) satisfies $x + $y = 4
This quantified expression may either return true
or raise a type
error, since its test expression returns true
for
one variable binding and raises a type error for another:
some $x in (1, 2, "cat") satisfies $x * 2 = 4
This quantified expression may either return false
or raise a type
error, since its test expression returns false
for
one variable binding and raises a type error for another:
every $x in (1, 2, "cat") satisfies $x * 2 = 4
This quantified expression contains a type declaration that is not
satisfied by every item in the test expression. If the Static
Typing Feature is implemented, this expression raises a
type error during
the static analysis phase. Otherwise, the
expression may either return true
or raise a type error during the
dynamic evaluation phase.
some $x as xs:integer in (1, 2, "cat") satisfies $x * 2 = 4
The try/catch expression provides error handling for dynamic
errors and type errors raised during dynamic evaluation, including
errors raised by the XQuery implementation and errors explicitly
raised in a query using the fn:error()
function.
| [78] | TryCatchExpr |
::= | TryClause CatchClause+ |
| [79] | TryClause |
::= | "try" "{" TryTargetExpr "}" |
| [80] | TryTargetExpr |
::= | Expr |
| [81] | CatchClause |
::= | "catch" CatchErrorList "{" Expr "}" |
| [82] | CatchErrorList |
::= | NameTest ("|"
NameTest)* |
A try/catch expression catches dynamic errors and type errors raised during dynamic
evaluation for expressions that are lexically contained within the
try
clause. If the target expression does not raise a
dynamic error or a type error, the result of the try/catch
expression is the result of the target expression.
If the target expression raises a dynamic error or a type error,
the result of the try/catch expression is obtained by evaluating
the first catch
clause that "matches" the error value,
as described below. A catch
clause with one or more
NameTests matches any error whose error code matches one of these
NameTests. For instance, if the error code is
err:FOER0000
, then it matches a catch
clause whose ErrorList is err:FOER0000 | err:FOER0001
.
Wildcards may be used in NameTests; thus, the error code
err:FOER0000
also matches a catch
clause
whose ErrorList is err:*
or *:FOER0000
or
*
.
Within the scope of the catch
clause, a number of
variables are implicitly declared, giving information about the
error that occurred. These variables are initialized as described
in the following table:
| Variable | Type | Value |
|---|---|---|
| err:code | xs:QName | The error code |
| err:description | xs:string? | A description of the error condition; an
empty sequence if no description is available (for example, if the
error function was called with one
argument). |
| err:value | item()* | Value associated with the error. For an error
raised by calling the error function, this is the
value of the third argument (if supplied). |
| err:module | xs:string? | The URI (or system ID) of the module containing the expression where the error occurred, or an empty sequence if the information is not available. |
| err:line-number | xs:integer? | The line number within the stylesheet module of the instruction where the error occurred, or an empty sequence if the information is not available. The value may be approximate. |
| err:column-number | xs:integer? | The column number within the stylesheet module of the instruction where the error occurred, or an empty sequence if the information is not available. The value may be approximate. |
| err:additional | item()* | Implementation-defined. This variable must be bound so that a query can reference it without raising an error. The purpose of this variable is to allow implementations to provide any additional information that might be useful. |
Try/catch expressions have a special rule for propagating dynamic errors. The try/catch expression ignores any dynamic errors encountered in catch clauses other than the first catch clause that matches an error raised by the try clause, and these catch clause expressions need not be evaluated.
Static errors are not caught by the try/catch expression.
If a function call occurs within a try
clause,
errors raised by evaluating the corresponding function are caught
by the try/catch expression. If a variable reference is used in a
try
clause, errors raised by binding a value to the
variable are not caught unless the binding expression occurs within
the try
clause.
Note:
The presence of a try/catch expression does not prevent an implementation from using a lazy evaluation strategy, nor does it prevent an optimizer performing expression rewrites. However, if the evaluation of an expression inside a try/catch is rewritten or deferred in this way, it must take its try/catch context with it. Similarly, expressions that were written outside the try/catch expression may be evaluated inside the try/catch, but only if they retain their original try/catch behavior. The presence of a try/catch does not change the rules that allow the processor to evaluate expressions in such a way that may avoid the detection of some errors.
Here are some examples of try/catch expressions.
A try/catch expression without a CatchErrorList catches any error:
try { $x cast as xs:integer } catch * { 0 }
The CatchErrorList in this try/catch expression specifies that
only err:FORG0001
is caught:
try { $x cast as xs:integer } catch err:FORG0001 { 0 }
The CatchErrorList in this try/catch expression specifies that
errors err:FORG0001
and err:XPTY0004
are
caught:
try { $x cast as xs:integer } catch err:FORG0001 | err:XPTY0004 { 0 }
Note:
In some implementations, err:XPTY0004
is detected
during static evaluation; it can only be caught if it is raised
during dynamic evaluation.
This try/catch expression shows how to return information about the error using implicitly defined error variables. Since the CatchErrorList is a wildcard, it catches any error:
try { fn:error(fn:QName('http://www.w3.org/2005/xqt-errors', 'err:FOER0000')) } catch * { $err:code, $err:value, " module: ", $err:module, "(", $err:line-number, ",", $err:column-number, ")" }
Errors raised by using the result of a try/catch expression are
not caught, since they are outside the scope of the
try
expression.
declare function local:thrice($x as xs:integer) as xs:integer { 3*$x }; local:thrice(try { "oops" } catch * { 3 } )
In this example, the try block succeeds, returning the string "oops", which is not a valid argument to the function.
In addition to their use in function
parameters and results, sequence types are used in instance
of
, typeswitch
,
cast
, castable
, and treat
expressions.
| [92] | InstanceofExpr |
::= | TreatExpr (
"instance" "of" SequenceType )? |
The boolean operator instance of
returns
true
if the value of its first operand matches the
SequenceType in its second
operand, according to the rules for SequenceType matching; otherwise it
returns false
. For example:
5 instance of xs:integer
This example returns true
because the given value
is an instance of the given type.
5 instance of xs:decimal
This example returns true
because the given value
is an integer literal, and xs:integer
is derived by
restriction from xs:decimal
.
{5} instance of xs:integer
This example returns false
because the given value
is an element rather than an integer.
(5, 6) instance of xs:integer+
This example returns true
because the given
sequence contains two integers, and is a valid instance of the
specified type.
. instance of element()
This example returns true
if the context item is an
element node or false
if the context item is defined
but is not an element node. If the context item is absentDM30,
a dynamic
error is raised [err:XPDY0002].
| [74] | TypeswitchExpr |
::= | "typeswitch" "(" Expr
")" CaseClause+ "default"
("$" VarName)? "return"
ExprSingle |
| [75] | CaseClause |
::= | "case" ("$" VarName
"as")? SequenceTypeUnion "return"
ExprSingle |
| [76] | SequenceTypeUnion |
::= | SequenceType
("|" SequenceType)* |
The typeswitch expression chooses one of several expressions to evaluate based on the dynamic type of an input value.
In a typeswitch
expression, the
typeswitch
keyword is followed by an expression
enclosed in parentheses, called the operand expression. This
is the expression whose type is being tested. The remainder of the
typeswitch
expression consists of one or more
case
clauses and a default
clause.
Each case
clause specifies one or
more SequenceTypes
followed by a return
expression. [Definition: The effective case in a
typeswitch
expression is the first case
clause in which the value of the operand expression matches a
SequenceType in the
SequenceTypeUnion of the
case
clause, using the rules of SequenceType matching. ] The value
of the typeswitch
expression is the value of the
return
expression in the effective case. If the value
of the operand expression does not match any SequenceType named in a
case
clause, the value of the typeswitch
expression is the value of the return
expression in
the default
clause.
In a case
or default
clause, if the
value to be returned depends on the value of the operand
expression, the clause must specify a variable name. Within the
return
expression of the case
or
default
clause, this variable name is bound to the
value of the operand expression. Inside a case
clause,
the static type
of the variable is the union of the SequenceTypes named in the
SequenceTypeUnion. Inside
a default
clause, the static type of the variable is
the same as the static type of the operand expression. If the value
to be returned by a case
or default
clause does not depend on the value of the operand expression, the
clause need not specify a variable.
The scope of a variable binding in a case
or
default
clause comprises that clause. It is not an
error for more than one case
or default
clause in the same typeswitch
expression to bind
variables with the same name.
A special rule applies to propagation of dynamic errors by
typeswitch
expressions. A typeswitch
expression ignores (does not raise) any dynamic errors encountered
in case
clauses other than the effective case.
Dynamic errors encountered in the default
clause are
raised only if there is no effective case. An implementation is
permitted to raise dynamic errors in the operand expressions of
case clauses that occur before the effective case, but not required to do
so.
The following example shows how a
typeswitch
expression might be used to process an
expression in a way that depends on its dynamic type.
typeswitch($customer/billing-address) case $a as element(*, USAddress) return $a/state case $a as element(*, CanadaAddress) return $a/province case $a as element(*, JapanAddress) return $a/prefecture default return "unknown"
The following example shows a union of sequence types in a single case:
typeswitch($customer/billing-address) case $a as element(*, USAddress) | element(*, AustraliaAddress) | element(*, MexicoAddress) return $a/state case $a as element(*, CanadaAddress) return $a/province case $a as element(*, JapanAddress) return $a/prefecture default return "unknown"
| [95] | CastExpr |
::= | UnaryExpr ( "cast"
"as" SingleType
)? |
| [166] | SingleType |
::= | SimpleTypeName "?"? |
| [171] | AtomicOrUnionType |
::= | EQName |
Occasionally it is necessary to convert a value to a specific
datatype. For this purpose, XQuery 3.0 provides a cast
expression that creates a new value of a specific type based on an
existing value. A cast
expression takes two operands:
an input expression and a target type. The type of
the atomized value of the input expression is called
the input type. The SimpleTypeName must be the name of
a type defined in the in-scope schema types, and it must be a
simple type [err:XQST0052]. In addition, the target
type cannot be xs:NOTATION
,
xs:anySimpleType
, or
xs:anyAtomicType
[err:XPST0080]. The optional occurrence indicator
"?
" denotes that an empty sequence is permitted. If
the target type is a lexical QName that has no
namespace prefix, it is considered to be in the default
element/type namespace.
Casting a node to xs:QName
can cause
surprises because it uses the static context of the cast
expression to provide the namespace bindings for this operation.
Instead of casting to xs:QName
, it is generally
preferable to use the fn:QName
function, which
allows the namespace context to be taken from the document
containing the QName.
The semantics of the cast
expression are as
follows:
The input expression is evaluated.
The result of the first step is atomized.
If the result of atomization is a sequence of more than one atomic value, a type error is raised [err:XPTY0004].
If the result of atomization is an empty sequence:
If ?
is specified after the target type, the result
of the cast
expression is an empty sequence.
If ?
is not specified after the target type, a
type error is
raised [err:XPTY0004].
If the result of atomization is a single atomic value, the result of the cast expression depends on the input type and the target type. In general, the cast expression attempts to create a new value of the target type based on the input value. Only certain combinations of input type and target type are supported. A summary of the rules are listed below—the normative definition of these rules is given in [XQuery and XPath Functions and Operators 3.0]. For the purpose of these rules, an implementation may determine that one type is derived by restriction from another type either by examining the in-scope schema definitions or by using an alternative, implementation-dependent mechanism such as a data dictionary.
cast
is supported for the combinations of input
type and target type listed in
Section 18.1 Casting from primitive types to primitive types
FO30. For each of these combinations,
both the input type and the target type are primitive schema types. For example,
a value of type xs:string
can be cast into the schema
type xs:decimal
. For each of these built-in
combinations, the semantics of casting are specified in [XQuery and XPath Functions and Operators
3.0].
cast
is supported if the input type is a
non-primitive atomic type that is derived by restriction from the
target type. In this case, the input value is mapped into the value
space of the target type, unchanged except for its type. For
example, if shoesize
is derived by restriction from
xs:integer
, a value of type shoesize
can
be cast into the schema type xs:integer
.
cast
is supported if the target type is a
non-primitive atomic type and the input type is
xs:string
or xs:untypedAtomic
. The input
value is first converted to a value in the lexical space of the
target type by applying the whitespace normalization rules for the
target type (as defined in [XML Schema
1.0] or [XML Schema 1.1]). The
lexical value is then converted to the value space of the target
type using the schema-defined rules for the target type. If the
input value fails to satisfy some facet of the target type, a
dynamic error
may be raised as specified in [XQuery
and XPath Functions and Operators 3.0].
cast
is supported to any target type if the input
type is xs:string
or xs:untypedAtomic
.
The target type may be an atomic type, a union type, or a list
type. The semantics are based on the rules for validation in
[XML Schema 1.0] or [XML Schema 1.1].
The effect of casting a string S to a simple type T is the same as constructing an element or attribute node whose string value is S, validating it using T as the governing type, and atomizing the resulting node. The result may be a single atomic value or (if list types are involved) a sequence of zero or more atomic values.
If the target type is namespace-sensitive, then the namespace bindings in the static context will be used to resolve any namespace prefix found in the supplied string.
cast
is supported if the target type is a
non-primitive atomic type that is derived by restriction from the
input type. The input value must satisfy all the facets of the
target type (in the case of the pattern facet, this is checked by
generating a string representation of the input value, using the
rules for casting to xs:string
). The resulting value
is the same as the input value, but with a different dynamic type.
If a primitive type P1 can be cast into a primitive type P2, then any type derived by restriction from P1 can be cast into any type derived by restriction from P2, provided that the facets of the target type are satisfied. First the input value is cast to P1 using rule (b) above. Next, the value of type P1 is cast to the type P2, using rule (a) above. Finally, the value of type P2 is cast to the target type, using rule (d) above.
For any combination of input type and target type that is not in
the above list, a cast
expression raises a type error [err:XPTY0004].
If casting from the input type to the target type is supported
but nevertheless it is not possible to cast the input value into
the value space of the target type, a dynamic error is raised.
[err:FORG0001] This includes the case when any facet of the target
type is not satisfied. For example, the expression
"2003-02-31" cast as xs:date
would raise a dynamic error.
| [94] | CastableExpr |
::= | CastExpr (
"castable" "as" SingleType
)? |
| [166] | SingleType |
::= | SimpleTypeName "?"? |
XQuery 3.0 provides an expression that tests whether a given
value is castable into a given target type. The
SimpleTypeName must be the name of a type defined in the in-scope schema
types, and the type must be simple
[err:XQST0052]. In
addition, the target type cannot be xs:NOTATION
xs:anySimpleType
, or
xs:anyAtomicType
[err:XPST0080]. The optional occurrence indicator
"?
" denotes that an empty sequence is permitted.
The expression E castable as T
returns
true
if the result of evaluating E
can be
successfully cast into the target type T
by using a
cast
expression; otherwise it returns
false
. If evaluation of E
fails with a
dynamic error, the castable
expression returns
false. The castable
expression can be used as a
predicate to avoid errors at
evaluation time. It can also be used to select an appropriate type
for processing of a given value, as illustrated in the following
example:
if ($x castable as hatsize) then $x cast as hatsize else if ($x castable as IQ) then $x cast as IQ else $x cast as xs:string
For every generalized atomic type in the
in-scope schema
types (except xs:NOTATION
and
xs:anyAtomicType
, which are not instantiable), a
constructor function is implicitly defined. In each case,
the name of the constructor function is the same as the name of its
target type (including namespace). The signature of the constructor
function for type T is as follows:
T($arg as xs:anyAtomicType?) as T?
[Definition: The constructor
function for a given type is used to convert instances of other
atomic types into the given type. The semantics of the constructor
function call T($arg)
are defined to be equivalent to
the expression (($arg) cast as T?)
.]
The following examples illustrate the use of constructor functions:
This example is equivalent to ("2000-01-01" cast as
xs:date?)
.
xs:date("2000-01-01")
This example is equivalent to (($floatvalue * 0.2E-5) cast
as xs:decimal?)
.
xs:decimal($floatvalue * 0.2E-5)
This example returns an xs:dayTimeDuration
value
equal to 21 days. It is equivalent to ("P21D" cast as
xs:dayTimeDuration?)
.
xs:dayTimeDuration("P21D")
If usa:zipcode
is a user-defined atomic type in the
in-scope schema
types, then the following expression is equivalent to the
expression ("12345" cast as usa:zipcode?)
.
usa:zipcode("12345")
Note:
An instance of an atomic type that is not in a namespace can be constructed in either of the following ways:
By using a cast
expression, if the default
element/type namespace is absentDM30.
(See 4.14
Default Namespace Declaration for how to undeclare the
default element/type
namespace).
17 cast as apple
By using a constructor function, if the default function namespace is absentDM30. (See 4.14 Default Namespace Declaration for how to undeclare the default function namespace).
apple(17)
| [93] | TreatExpr |
::= | CastableExpr (
"treat" "as" SequenceType
)? |
XQuery 3.0 provides an expression called treat
that
can be used to modify the static type of its operand.
Like cast
, the treat
expression takes
two operands: an expression and a SequenceType. Unlike
cast
, however, treat
does not change the
dynamic type or
value of its operand. Instead, the purpose of treat
is
to ensure that an expression has an expected dynamic type at
evaluation time.
The semantics of expr1
treat
as
type1
are as follows:
During static analysis:
The static
type of the treat
expression is
type1
. This enables the expression to be
used as an argument of a function that requires a parameter of
type1
.
During expression evaluation:
If expr1
matches
type1
, using the rules for SequenceType matching, the
treat
expression returns the value of
expr1
; otherwise, it raises a dynamic error
[err:XPDY0050]. If
the value of expr1
is returned, its identity
is preserved. The treat
expression ensures that the
value of its expression operand conforms to the expected type at
run-time.
Example:
$myaddress treat as element(*, USAddress)
The static
type of $myaddress
may be element(*,
Address)
, a less specific type than element(*,
USAddress)
. However, at run-time, the value of
$myaddress
must match the type element(*,
USAddress)
using rules for SequenceType matching;
otherwise a dynamic error is raised [err:XPDY0050].
!
)| [106] | SimpleMapExpr |
::= | PathExpr ("!"
PathExpr)* |
The simple map operator "!
" is used for simple
mappings. Both its left-hand side expression and its
right-hand-side expression may return a mixed sequence of nodes and
non-nodes.
Each operation E1!E2
is evaluated as follows:
Expression E1
is evaluated to a sequence
S
. Each item in S
then serves in turn to
provide an inner focus (the item as the context item, its position
in S
as the context position, the length of
S
as the context size) for an evaluation of
E2
in the dynamic context. The sequences resulting
from all the evaluations of E2
are combined as
follows: Every evaluation of E2
returns a (possibly
empty) sequence of items. These sequences are concatenated and
returned. If ordering mode is ordered, the returned sequence
preserves the orderings within and among the subsequences generated
by the evaluations of E2
; otherwise the order of the
returned sequence is implementation-dependent.
Simple map operators have functionality similar to <IP_ADDRESS> Path operator (/). The following table summarizes the differences between these two operators
| Operator | Path operator (E1 / E2 ) |
Simple map operator (E1 ! E2 ) |
|---|---|---|
| E1 | Any sequence of nodes | Any sequence of items |
| E2 | Either a sequence of nodes or a sequence of non-node items | A sequence of items |
| Additional processing | Duplicate elimination and document ordering | Simple sequence concatenation |
The following examples illustrate the use of simple map operators combined with path expressions.
child::div1 / child::para / string() ! concat("id-",
.)
Selects the para
element children of the
div1
element children of the context node; that is,
the para
element grandchildren of the context node
that have div1
parents. It then outputs the strings
obtained by prepending "id-"
to each of the string
values of these grandchildren.
$emp ! (@first, @middle, @last)
Returns the values of the attributes first
,
middle
, and last
for element
$emp
, in the order given. (The /
operator
here returns the attributes in an unpredictable order.)
$docs ! ( //employee)
Returns all the employees within all the documents identified by the variable docs, in document order within each document, but retaining the order of documents.
avg( //employee / salary ! translate(., '$', '') !
number(.))
Returns the average salary of the employees, having converted
the salary to a number by removing any $
sign and then
converting to a number. (The second occurrence of !
could not be written as /
because the left-hand
operand of /
cannot be an atomic value.)
| [101] | ValidateExpr |
::= | "validate" (ValidationMode | ("type"
TypeName))? "{" Expr "}" |
| [102] | ValidationMode |
::= | "lax" | "strict" |
A validate
expression can be used to validate a
document node or an element node with respect to the in-scope schema
definitions, using the schema validation process defined in
[XML Schema 1.0] or [XML Schema 1.1]. If the operand of a
validate
expression does not evaluate to exactly one
document or element node, a type error is raised [err:XQTY0030]. In this specification, the
node that is the operand of a validate
expression is
called the operand node.
A validate
expression returns a new node with its
own identity and with no parent. The new node and its descendants
are given type annotation that are generated by
applying a validation process to the operand node. In some cases,
default values may also be generated by the validation process.
A validate
expression may optionally specify a
validation mode. The
default validation mode
(applicable when no type name is provided) is
strict
.
A validate
expression may optionally specify a
TypeName. This type name must
be found in the in-scope schema definitions; if it is not, a
static error is
raised [err:XQST0104]. If the type name is unprefixed,
it is interpreted as a name in the default namespace for elements
and types.
The result of a validate
expression is defined by
the following rules.
If the operand node is a document node, its children must consist of exactly one element node and zero or more comment and processing instruction nodes, in any order; otherwise, a dynamic error [err:XQDY0061] is raised.
The operand node is converted to an XML Information Set ([XML Infoset]) according to the "Infoset Mapping" rules defined in [XQuery and XPath Data Model (XDM) 3.0]. Note that this process discards any existing type annotations. Validity assessment is carried out on the root element information item of the resulting Infoset, using the in-scope schema definitions as the effective schema. The process of validation applies recursively to contained elements and attributes to the extent required by the effective schema.
If a type name is provided, schema-validity assessment is carried out according to the rules defined in [XML Schema 1.0] or [XML Schema 1.1] Part 1, section 3.3.4 "Element Declaration Validation Rules", "Validation Rule: Schema-Validity Assessment (Element)", clauses 1.2 and 2, using this type definition as the "processor-stipulated type definition" for validation.
When no type name is provided:
If validation mode is
strict
, then there must be a top-level element
declaration in the in-scope element declarations that matches the
root element information item in the Infoset, and schema-validity
assessment is carried out using that declaration in accordance with
[XML Schema 1.0] Part 1, section 5.2,
"Assessing Schema-Validity", item 2, or [XML
Schema 1.1] Part 1, section 5.2, "Assessing Schema-Validity",
"element-driven validation". If there is no such element
declaration, a dynamic error is raised [err:XQDY0084].
If validation mode is
lax
, then schema-validity assessment is carried out in
accordance with [XML Schema 1.0] Part 1,
section 5.2, "Assessing Schema-Validity", item 3, or [XML Schema 1.1] Part 1, section 5.2, "Assessing
Schema-Validity", "lax wildcard validation".
If validation mode is
lax
and the root element information item has neither
a top-level element declaration nor an xsi:type
attribute, [XML Schema 1.0] or [XML Schema 1.1] defines the recursive checking
of children and attributes as optional. During processing of an
XQuery validate
expression, this recursive checking is
required.
If the operand node is an element node, the validation rules named "Validation Root Valid (ID/IDREF)" is not applied. This means that document-level constraints relating to uniqueness and referential integrity are not enforced.
There is no check that the document contains unparsed entities
whose names match the values of nodes of type
xs:ENTITY
or xs:ENTITIES
.
Note:
Validity assessment is affected by the presence or absence of
xsi:type
attributes on the elements being validated,
and may generate new information items such as default
attributes.
The outcome of the validation expression depends on
the validity
property of the root element
information item in the PSVI that results from the validation
process.
If the validity
property of the root element
information item is valid
, or if validation mode is
lax
and the validity
property of the root
element information item is notKnown
, the PSVI is
converted back into an XDM instance as described in [XQuery and XPath Data Model (XDM) 3.0]
Section 3.3, "Construction from a PSVI". The resulting node (a new
node of the same kind as the operand node) is returned as the
result of the validate
expression.
Otherwise, a dynamic error is raised [err:XQDY0027].
Note:
The effect of these rules is as follows, where the validated element means either the operand node or (if the operand node is a document node) its element child.:
If validation mode is
strict
, the validated element must have a top-level
element declaration in the effective schema, and must conform to
this declaration.
If validation mode is
lax
, the validated element must conform to its
top-level element declaration if such a declaration exists in the
effective schema. If validation mode is
lax
and there is no top-level element declaration for
the element, and the element has an xsi:type
attribute, then the xsi:type
attribute must name a
top-level type definition in the effective schema, and the element
must conform to that type.
If a type name is specified in the validate expression, no
attempt is made to locate an element declaration matching the name
of the validated element; the element can have any name, and its
content is validated against the named type. If the
type name is xs:untyped
, no are created as a result of
validation; the result of validate type xs:untyped { $x
}
is the value of $x
with all type annotatins
removed.
Note:
During conversion of the PSVI into an XDM instance after validation,
any element information items whose validity property is
notKnown
are converted into element nodes with
type
annotation xs:anyType
, and any attribute
information items whose validity property is notKnown
are converted into attribute nodes with type annotation
xs:untypedAtomic
, as described in Section
<IP_ADDRESS> Element and Attribute Node Types
DM30.
[Definition: An extension expression is an expression whose semantics are implementation-defined.] Typically a particular extension will be recognized by some implementations and not by others. The syntax is designed so that extension expressions can be successfully parsed by all implementations, and so that fallback behavior can be defined for implementations that do not recognize a particular extension.
| [103] | ExtensionExpr |
::= | Pragma+ "{" Expr? "}" |
| [104] | Pragma |
::= | "(#" S? EQName (S
PragmaContents)?
"#)" |
| [105] | PragmaContents |
::= | (Char* - (Char* '#)'
Char*)) |
An extension expression consists of one or more pragmas,
followed by an expression enclosed in curly braces. [Definition: A
pragma is denoted by the delimiters (#
and
#)
, and consists of an identifying EQName followed by
implementation-defined content.]
The content of a pragma may consist of any string of characters
that does not contain the ending delimiter #)
. If the
EQName of a pragma is a lexical QName, it must resolve to a namespace URI
and local name, using the statically known namespaces
[err:XPST0081].
Note:
Since there is no default namespace for pragmas, a pragma's EQName must provide a BracedURILiteral or a namespace prefix.
Each implementation recognizes an implementation-defined set of namespace URIs used to denote pragmas.
If the namespace URI of a pragma's expanded QName is not recognized by the implementation as a pragma namespace, then the pragma is ignored. If all the pragmas in an ExtensionExpr are ignored, then the value of the ExtensionExpr is the value of the expression enclosed in curly braces; if this expression is absent, then a static error is raised [err:XQST0079].
If an implementation recognizes the namespace of one or more pragmas in an ExtensionExpr, then the value of the ExtensionExpr, including its error behavior, is implementation-defined. For example, an implementation that recognizes the namespace of a pragma's expanded QName, but does not recognize the local part of the name, might choose either to raise an error or to ignore the pragma.
It is a static error [err:XQST0013] if an implementation recognizes a pragma but determines that its content is invalid.
If an implementation recognizes a pragma, it must report any static errors in the following expression even if it will not evaluate that expression (however, static type errors are raised only if the Static Typing Feature is in effect.)
Note:
The following examples illustrate three ways in which extension expressions might be used.
A pragma can be used to furnish a hint for how to evaluate the following expression, without actually changing the result. For example:
declare namespace exq = "http://example.org/XQueryImplementation"; (# exq:use-index #) { $bib/book/author[name='Berners-Lee'] }
An implementation that recognizes the exq:use-index
pragma might use an index to evaluate the expression that follows.
An implementation that does not recognize this pragma would
evaluate the expression in its normal way.
A pragma might be used to modify the semantics of the following
expression in ways that would not (in the absence of the pragma) be
conformant with this specification. For example, a pragma might be
used to permit comparison of xs:duration
values using
implementation-defined semantics (this would normally be an error).
Such changes to the language semantics must be scoped to the
expression contained within the curly braces following the
pragma.
A pragma might contain syntactic constructs that are evaluated in place of the following expression. In this case, the following expression itself (if it is present) provides a fallback for use by implementations that do not recognize the pragma. For example:
declare namespace exq = "http://example.org/XQueryImplementation"; for $x in (# exq:distinct //city by @country #) { //city[not(@country = preceding::city/@country)] } return f:show-city($x)
Here an implementation that recognizes the pragma will return
the result of evaluating the proprietary syntax exq:distinct
//city by @country
, while an implementation that does not
recognize the pragma will instead return the result of the
expression //city[not(@country =
preceding::city/@country)]
. If no fallback expression is
required, or if none is feasible, then the expression between the
curly braces may be omitted, in which case implementations that do
not recognize the pragma will raise a static error.
| [1] | Module |
::= | VersionDecl?
(LibraryModule | MainModule) |
| [3] | MainModule |
::= | Prolog QueryBody |
| [4] | LibraryModule |
::= | ModuleDecl
Prolog |
| [6] | Prolog |
::= | ((DefaultNamespaceDecl |
Setter | NamespaceDecl | Import) Separator)* ((ContextItemDecl | AnnotatedDecl | OptionDecl) Separator)* |
| [8] | Setter |
::= | BoundarySpaceDecl | DefaultCollationDecl |
BaseURIDecl | ConstructionDecl | OrderingModeDecl | EmptyOrderDecl | CopyNamespacesDecl |
DecimalFormatDecl |
| [20] | Import |
::= | SchemaImport |
ModuleImport |
| [7] | Separator |
::= | ";" |
| [38] | QueryBody |
::= | Expr |
A query can be assembled from one or more fragments called modules. [Definition: A module is a fragment of XQuery code that conforms to the Module grammar and can independently undergo the static analysis phase described in 2.2.3 Expression Processing. Each module is either a main module or a library module.]
[Definition: A main module consists of a Prolog followed by a Query Body.] A query has exactly one main module. In a main module, the Query Body can be evaluated. It is evaluated with respect to the static and dynamic contexts of the main module in which it is found, and its value is the result of the query.
[Definition: A module that does not contain a Query Body is called a library module. A library module consists of a module declaration followed by a Prolog.] A library module cannot be evaluated directly; instead, it provides function and variable declarations that can be imported into other modules.
The XQuery syntax does not allow a module to contain both a module declaration and a Query Body.
[Definition: A Prolog is a series of declarations and imports that define the processing environment for the module that contains the Prolog.] Each declaration or import is followed by a semicolon. A Prolog is organized into two parts.