In XQuery, each function and operator expects its arguments to be of a particular type. However, this is not as rigid as it may sound since there are a number of type conversions that happen automatically. They are discussed in this section.
Functions and operators that expect a value of a particular type also accept a value of one of its derived types. This is known as subtype substitution.
For example, the upper-case
function expects an xs:string
as an argument, but you can pass a value whose type is derived by restriction from xs:string
, such as xs:NMTOKEN
. This also works for complex types. A function expecting an element of type ProductType
also accepts an element of type UmbrellaType
, if UmbrellaType
is derived by restriction from ProductType
. Note that the value retains its original type; it is not actually cast to another type.
When two values of different numeric types are compared or used in the same operation, one is promoted to the type of the other. An xs:decimal
value can be promoted to the xs:float
or xs:double
type, and an xs:float
value can be promoted to the xs:double
type. For example, the expression 1.0 + 1.2E0
adds an xs:decimal
value (1.0
) to an xs:double
value. The xs:decimal
value is promoted to xs:double
before the expression is evaluated. Numeric type promotion happens automatically in arithmetic expressions, comparison expressions, and function calls.
In addition, values of type xs:anyURI
are automatically promoted to xs:string
in comparison expressions and function calls. Unlike subtype substitution, type promotion results in the type of a value changing.
In some cases, an untyped value is automatically cast to a specific type. This occurs in function calls, as well as in comparison and arithmetic expressions. For example, if you call the upper-case
function with an untyped value, it is automatically cast to xs:string
. If you add an untyped value to a number, as in <a>3</a> + 2
, the untyped value 3
is cast to xs:integer
, and the expression returns 5
.
Note that typed values are not automatically cast. For example, "3" + 2
will not automatically cast the string 3
to the number 3, even though this is theoretically possible. One exception is the concat
function, which automatically casts its arguments to strings. But that's special behavior of this particular function, not something that happens implicitly on the function call.
Atomization occurs when a function or operator expects an atomic value and receives a node instead. Specifically, it is used in:
Arithmetic operations
Comparisons
Function calls and returns
Cast expressions and constructors
Name expressions in computed constructors
Atomization involves extracting the typed value of one or more elements or attributes to return one or more atomic values. For example:
<el>3</el> + 5
returns the value 8
because the value 3
is extracted from the el
element during atomization.
Also:
substring(<e2>query</e2>, 2, 3)
returns uer
because the string query
is extracted from the e2
element. These two examples work if e1
and e2
are untyped, because their so-called typed values would be instances of xs:untypedAtomic
, and would be cast to the type required by the operation. They would work equally well if e1
had the type xs:integer
, and e2
had the type xs:string
, in which case no casting would need to take place.
It is often useful to treat a sequence as a Boolean value. For example, if you want to determine whether your catalog
element contains any products whose price is less than $20, you might use the expression:
if (doc("prices.xml")//prod[price < 20]) then <bargain-bin>{local:getBargains( )}</bargain-bin> else ( )
In this case, the result of the path expression doc("prices.xml")//prod[price < 20]
is a sequence of elements that match the criteria. However, the if
expression simply needs a yes/no answer regarding whether there are any elements that match the criteria. In this case, the sequence is automatically converted to its effective Boolean value, which essentially indicates whether it is empty.
Sequences are automatically interpreted as Boolean values in:
Conditional (if-then-else) expressions
Logical (and/or) expressions
where
clauses of FLWORs
Quantified (some/every) expressions
The argument to the not
function
The predicates of path expressions
In addition, the boolean
function can be used to explicitly convert a sequence to its effective Boolean value. The effective Boolean value of a sequence is false
if it is:
The empty sequence
A single, atomic value of type xs:boolean
that is equal to false
A single, atomic value of type xs:string
that is a zero-length string (""
)
A single, atomic value with a numeric type that is equal to 0 or NaN
The effective Boolean value is undefined on a sequence of more than one item whose first item is an atomic value, and on individual atomic values whose type is not numeric, untyped, or xs:string
. If the processor attempts to evaluate the effective Boolean value, and it is undefined, a type error is raised.
In all other cases, the effective Boolean value is true
. This includes a sequence of one or more items whose first item is a node or a single atomic value other than those described in the preceding list. Table 11-1 shows some examples.
Table 11-1. Examples of effective Boolean value
Example |
Effective Boolean value |
---|---|
( ) |
false |
false( ) |
false |
true( ) |
true |
"" |
false |
"false" |
true |
"x" |
true |
0 |
false |
xs:float("NaN") |
false |
(false() or false( )) |
false |
doc("prices.xml")/* |
true |
<a>false</a> |
true |
(false(), false(), false( )) |
Error |
1, 2, 3 |
Error |
xs:date("2007-01-15") |
Error |
Note that a node that contains a false
atomic value is not the same thing as a false
atomic value by itself. In the <a>false</a>
example in Table 11-1, the effective Boolean value is true
because a
is an element node, not an atomic value of type xs:boolean
. This is true even if the a
element is declared to be of type xs:boolean
.
When you call a function, sometimes the type of an argument differs from the type specified in the function signature. For example, you can pass an xs:integer
to a function that expects an xs:decimal
. Alternatively, you can pass an element that contains a string to a function that expects just a string. XQuery defines rules, known as function conversion rules,
for converting arguments to the expected type. These function conversion rules apply only if the function expects an atomic value (or sequence of atomic values).
In fact, these function conversion rules use the various methods of type conversion and matching that are described in the preceding sections. They are put together here to show the sequential process that takes place for each argument when a function is called.
Atomization is performed on the argument sequence, resulting in a sequence of atomic values.
Casting of untyped values is performed. For example, the untyped value 12
can be cast to xs:integer
. As noted above, typed values are not cast to other types.
If the expected type is numeric or xs:string
, type promotion may be performed. This means that a value of type xs:decimal
can be promoted to xs:float
, and xs:float
can be promoted to xs:double
. A value of type xs:anyURI
can be promoted to xs:string
.
Note that these rules do not cover converting a value to the base type from which its type is derived. For example, if an xs:unsignedInt
value is passed to a function that expects an xs:integer
, the value is not converted to xs:integer
. However, subtype substitution does occur, and the function accepts this value.
The reverse is not true; you cannot pass an xs:integer
value to a function that expects an xs:unsignedInt
, even if the integer you pass meets all the tests for an xs:unsignedInt
. The value must be explicitly cast to xs:unsignedInt
.
As an example of the function conversion rules, if a function expects an argument of type xs:decimal?
, it accepts any of the following:
An atomic value of type xs:decimal
The empty sequence, because the occurrence indicator (?) allows for it
An atomic value of type dty:myDecimal
(derived from xs:decimal
) because the sequence type xs:decimal?
matches derived types as well
An atomic value of type xs:integer
(derived from xs:decimal
) because the sequence type xs:decimal?
matches derived types as well
An atomic value of type dty:myInteger
(derived from xs:integer
) because the sequence type xs:decimal?
matches derived types as well
An untyped atomic value, whose value is 12.5
, because it is cast to xs:decimal
(step 2)
An element of type xs:decimal
, because its value is extracted (step 1)
An untyped attribute, whose value is 12
, because its value is extracted (step 1) and cast to xs:decimal
(step 2)
An untyped element whose only content is 12.5
, because its value is extracted (step 1) and cast to xs:decimal
(step 2)
A function expecting xs:decimal*
accepts a sequence of any combination of the above items. On the other hand, a function expecting xs:decimal?
does not accept:
An atomic value of type xs:string
, even if its value is 12.5
. This value must be explicitly cast to xs:decimal
or a type error is raised.
An atomic value of type xs:float
, because type promotion only works in one direction.
An untyped element whose only content is abc
, because its value cannot be cast to xs:decimal
.
An untyped element with no content, because its value ""
(not the empty sequence) cannot be cast to xs:decimal
.
A typed element whose type allows element-only content even if it has no children, because step 1 raises an error.
A sequence of multiple xs:decimal
values; only one item is allowed.
3.139.83.62