3 Types

The type system of XQuery 4.0 is based on [XML Schema 1.0] or [XML Schema 1.1].

[Definition: A sequence type is a type that can be expressed using the SequenceType syntax. Sequence types are used whenever it is necessary to refer to a type in an XQuery 4.0 expression. The term sequence type suggests that this syntax is used to describe the type of an XQuery 4.0 value, which is always a sequence.]

[Definition: An item type is a type that can be expressed using the ItemType syntax, which forms part of the SequenceType syntax. Item types match individual items.] With the exception of the generic types item(), which matches all items, and xs:error, which matches no items, the set of items matched by an item type consists either exclusively of atomic values, exclusively of nodes, or exclusively of function itemsDM31.

Note:

These definitions require a caveat: types defined in a schema may be anonymous, in which case they cannot be referenced directly using the ItemType or SequenceType syntax. For example an element that is validated against an anonymous complex type A conforms to an item type which could be written element(*, A) but for the fact that A is anonymous.

[Definition: A schema type is a type that is (or could be) defined using the facilities of [XML Schema 1.0] or [XML Schema 1.1] (including the built-in types).] A schema type can be used as a type annotation on an element or attribute node (unless it is a non-instantiable type such as xs:NOTATION or xs:anyAtomicType, in which case its derived types can be so used). Every schema type is either a complex type or a simple type; simple types are further subdivided into list types, union types, and atomic types (see [XML Schema 1.0] or [XML Schema 1.1] for definitions and explanations of these terms.)

[Definition: A generalized atomic type is a schema-defined type which is either (a) an atomic type or (b) a pure union type ].

[Definition: A pure union type is an XML Schema union type that satisfies the following constraints: (1) {variety} is union, (2) the {facets} property is empty, (3) no type in the transitive membership of the union type has {variety} list, and (4) no type in the transitive membership of the union type is a type with {variety} union having a non-empty {facets} property].

Note:

The definition of pure union type excludes union types derived by non-trivial restriction from other union types, as well as union types that include list types in their membership. Pure union types have the property that every instance of an atomic type defined as one of the member types of the union is also a valid instance of the union type.

Note:

The current (second) edition of XML Schema 1.0 contains an error in respect of the substitutability of a union type by one of its members: it fails to recognize that this is unsafe if the union is derived by restriction from another union.

This problem is fixed in XSD 1.1, but the effect of the resolution is that an atomic value labeled with an atomic type cannot be treated as being substitutable for a union type without explicit validation. This specification therefore allows union types to be used as item types only if they are defined directly as the union of a number of atomic types.

Generalized atomic types represent the intersection between the categories of sequence type and schema type. A generalized atomic type, such as xs:integer or my:hatsize, is both a sequence type and a schema type.

3.1 Predefined Schema Types

The schema types defined in Section 2.7.2 Predefined Types DM31 are summarized below.

The in-scope schema types in the static context are initialized with certain predefined schema types, including the built-in schema types in the namespace http://www.w3.org/2001/XMLSchema, which has the predefined namespace prefix xs. The schema types in this namespace are defined in [XML Schema 1.0] or [XML Schema 1.1] and augmented by additional types defined in [XQuery and XPath Data Model (XDM) 3.1]. Element and attribute declarations in the xs namespace are not implicitly included in the static context. The schema types defined in [XQuery and XPath Data Model (XDM) 3.1] are summarized below.

  1. [Definition: xs:untyped is used as the type annotation of an element node that has not been validated, or has been validated in skip mode.] No predefined schema types are derived from xs:untyped.

  2. [Definition: xs:untypedAtomic is an atomic type that is used to denote untyped atomic data, such as text that has not been assigned a more specific type.] An attribute that has been validated in skip mode is represented in the data model by an attribute node with the type annotation xs:untypedAtomic. No predefined schema types are derived from xs:untypedAtomic.

  3. [Definition: xs:dayTimeDuration is derived by restriction from xs:duration. The lexical representation of xs:dayTimeDuration is restricted to contain only day, hour, minute, and second components.]

  4. [Definition: xs:yearMonthDuration is derived by restriction from xs:duration. The lexical representation of xs:yearMonthDuration is restricted to contain only year and month components.]

  5. [Definition: xs:anyAtomicType is an atomic type that includes all atomic values (and no values that are not atomic). Its base type is xs:anySimpleType from which all simple types, including atomic, list, and union types, are derived. All primitive atomic types, such as xs:decimal and xs:string, have xs:anyAtomicType as their base type.]

    Note:

    xs:anyAtomicType will not appear as the type of an actual value in an XDM instance.

  6. [Definition: xs:error is a simple type with no value space. It is defined in Section 3.16.7.3 xs:error XS11-1 and can be used in the 3.4 Sequence Types to raise errors.]

The relationships among the schema types in the xs namespace are illustrated in Figure 2. A more complete description of the XQuery 4.0 type hierarchy can be found in Section 1.6 Type System FO31.

Type Hierarchy Diagram

Figure 2: Hierarchy of Schema Types used in XQuery 4.0.

3.2 Namespace-sensitive Types

[Definition: The namespace-sensitive types are xs:QName, xs:NOTATION, types derived by restriction from xs:QName or xs:NOTATION, list types that have a namespace-sensitive item type, and union types with a namespace-sensitive type in their transitive membership.]

It is not possible to preserve the type of a namespace-sensitive value without also preserving the namespace binding that defines the meaning of each namespace prefix used in the value. Therefore, XQuery 4.0 defines some error conditions that occur only with namespace-sensitive values. For instance, casting to a namespace-sensitive type raises a type error [err:FONS0004]FO31 if the namespace bindings for the result cannot be determined.

3.3 Typed Value and String Value

Every node has a typed value and a string value, except for nodes whose value is absentDM31. [Definition: The typed value of a node is a sequence of atomic values and can be extracted by applying the Section 2.4 fn:data FO31 function to the node.] [Definition: The string value of a node is a string and can be extracted by applying the Section 2.3 fn:string FO31 function to the node.]

An implementation may store both the typed value and the string value of a node, or it may store only one of these and derive the other as needed. The string value of a node must be a valid lexical representation of the typed value of the node, but the node is not required to preserve the string representation from the original source document. For example, if the typed value of a node is the xs:integer value 30, its string value might be "30" or "0030".

The typed value, string value, and type annotation of a node are closely related, and are defined by rules found in the following locations:

As a convenience to the reader, the relationship between typed value and string value for various kinds of nodes is summarized and illustrated by examples below.

  1. For text and document nodes, the typed value of the node is the same as its string value, as an instance of the type xs:untypedAtomic. The string value of a document node is formed by concatenating the string values of all its descendant text nodes, in document order.

  2. The typed value of a comment or processing instruction node is the same as its string value. It is an instance of the type xs:string.

  3. The typed value of an attribute node with the type annotation xs:anySimpleType or xs:untypedAtomic is the same as its string value, as an instance of xs:untypedAtomic. The typed value of an attribute node with any other type annotation is derived from its string value and type annotation using the lexical-to-value-space mapping defined in [XML Schema 1.0] or [XML Schema 1.1] Part 2 for the relevant type.

    Example: A1 is an attribute having string value "3.14E-2" and type annotation xs:double. The typed value of A1 is the xs:double value whose lexical representation is 3.14E-2.

    Example: A2 is an attribute with type annotation xs:IDREFS, which is a list datatype whose item type is the atomic datatype xs:IDREF. Its string value is "bar baz faz". The typed value of A2 is a sequence of three atomic values ("bar", "baz", "faz"), each of type xs:IDREF. The typed value of a node is never treated as an instance of a named list type. Instead, if the type annotation of a node is a list type (such as xs:IDREFS), its typed value is treated as a sequence of the generalized atomic type from which it is derived (such as xs:IDREF).

  4. For an element node, the relationship between typed value and string value depends on the node's type annotation, as follows:

    1. If the type annotation is xs:untyped or xs:anySimpleType or denotes a complex type with mixed content (including xs:anyType), then the typed value of the node is equal to its string value, as an instance of xs:untypedAtomic. However, if the nilled property of the node is true, then its typed value is the empty sequence.

      Example: E1 is an element node having type annotation xs:untyped and string value "1999-05-31". The typed value of E1 is "1999-05-31", as an instance of xs:untypedAtomic.

      Example: E2 is an element node with the type annotation formula, which is a complex type with mixed content. The content of E2 consists of the character "H", a child element named subscript with string value "2", and the character "O". The typed value of E2 is "H2O" as an instance of xs:untypedAtomic.

    2. If the type annotation denotes a simple type or a complex type with simple content, then the typed value of the node is derived from its string value and its type annotation in a way that is consistent with schema validation. However, if the nilled property of the node is true, then its typed value is the empty sequence.

      Example: E3 is an element node with the type annotation cost, which is a complex type that has several attributes and a simple content type of xs:decimal. The string value of E3 is "74.95". The typed value of E3 is 74.95, as an instance of xs:decimal.

      Example: E4 is an element node with the type annotation hatsizelist, which is a simple type derived from the atomic type hatsize, which in turn is derived from xs:integer. The string value of E4 is "7 8 9". The typed value of E4 is a sequence of three values (7, 8, 9), each of type hatsize.

      Example: E5 is an element node with the type annotation my:integer-or-string which is a union type with member types xs:integer and xs:string. The string value of E5 is "47". The typed value of E5 is 47 as an xs:integer, since xs:integer is the member type that validated the content of E5. In general, when the type annotation of a node is a union type, the typed value of the node will be an instance of one of the member types of the union.

      Note:

      If an implementation stores only the string value of a node, and the type annotation of the node is a union type, the implementation must be able to deliver the typed value of the node as an instance of the appropriate member type.

    3. If the type annotation denotes a complex type with empty content, then the typed value of the node is the empty sequence and its string value is the zero-length string.

    4. If the type annotation denotes a complex type with element-only content, then the typed value of the node is absentDM31. The fn:data function raises a type error [err:FOTY0012]FO31 when applied to such a node. The string value of such a node is equal to the concatenated string values of all its text node descendants, in document order.

      Example: E6 is an element node with the type annotation weather, which is a complex type whose content type specifies element-only. E6 has two child elements named temperature and precipitation. The typed value of E6 is absentDM31, and the fn:data function applied to E6 raises an error.

3.4 Sequence Types

Whenever it is necessary to refer to a type in an XQuery 4.0 expression, the SequenceType syntax is used.

[203]    SequenceType    ::=    ("empty-sequence" "(" ")")
| (ItemType OccurrenceIndicator?)
[205]    ItemType    ::=    AnyItemTest | TypeName | KindTest | FunctionTest | MapTest | ArrayTest | AtomicOrUnionType | RecordTest | LocalUnionType | EnumerationType | ParenthesizedItemType
[204]    OccurrenceIndicator    ::=    "?" | "*" | "+" /* xgc: occurrence-indicators */

With the exception of the special type empty-sequence(), a sequence type consists of an item type that constrains the type of each item in the sequence, and a cardinality that constrains the number of items in the sequence. Apart from the item type item(), which permits any kind of item, item types divide into node types (such as element()), generalized atomic types (such as xs:integer) and function types (such as function() as item()*).

Lexical QNames appearing in a sequence type have their prefixes expanded to namespace URIs by means of the statically known namespaces and (where applicable) the default element namespace or default type namespace . Equality of QNames is defined by the eq operator.

Item types representing element and attribute nodes may specify the required type annotations of those nodes, in the form of a schema type. Thus the item type element(*, us:address) denotes any element node whose type annotation is (or is derived from) the schema type named us:address.

The occurrence indicators '+', '*', and '?' bind to the last ItemType in the SequenceType, as described in occurrence-indicators constraint.

Here are some examples of sequence types that might be used in XQuery 4.0:

3.5 Sequence Type Matching

[Definition: SequenceType matching compares a value with an expected sequence type. ] For example, an instance of expression returns true if a given value matches a given sequence type, or false if it does not.

An XQuery 4.0 implementation must be able to determine relationships among the types in type annotations in an XDM instance and the types in the in-scope schema definitions (ISSD). An XQuery 4.0 implementation must be able to determine relationships among the types in ISSDs used in different modules of the same query.

[Definition: The use of a value that has a dynamic type that is a subtype of the expected type is known as subtype substitution.] Subtype substitution does not change the actual type of a value. For example, if an xs:integer value is used where an xs:decimal value is expected, the value retains its type as xs:integer.

The definition of SequenceType matching relies on a pseudo-function named derives-from( AT, ET ), which takes an actual simple or complex schema type AT and an expected simple or complex schema type ET, and either returns a boolean value or raises a type error [err:XPTY0004]. This function is defined as follows:

The rules for SequenceType matching are given below, with examples (the examples are for purposes of illustration, and do not cover all possible cases).

An OccurrenceIndicator specifies the number of items in a sequence, as follows:

As a consequence of these rules, any sequence type whose OccurrenceIndicator is * or ? matches a value that is an empty sequence.

3.6 Item Types

[205]    ItemType    ::=    AnyItemTest | TypeName | KindTest | FunctionTest | MapTest | ArrayTest | AtomicOrUnionType | RecordTest | LocalUnionType | EnumerationType | ParenthesizedItemType
[206]    AnyItemTest    ::=    "item" "(" ")"
[224]    TypeName    ::=    EQName
[208]    KindTest    ::=    DocumentTest
| ElementTest
| AttributeTest
| SchemaElementTest
| SchemaAttributeTest
| PITest
| CommentTest
| TextTest
| NamespaceNodeTest
| AnyKindTest
[210]    DocumentTest    ::=    "document-node" "(" (ElementTest | SchemaElementTest)? ")"
[218]    ElementTest    ::=    "element" "(" (NameTest ("," TypeName "?"?)?)? ")"
[219]    SchemaElementTest    ::=    "schema-element" "(" ElementDeclaration ")"
[220]    ElementDeclaration    ::=    ElementName
[215]    AttributeTest    ::=    "attribute" "(" (NameTest ("," TypeName)?)? ")"
[216]    SchemaAttributeTest    ::=    "schema-attribute" "(" AttributeDeclaration ")"
[217]    AttributeDeclaration    ::=    AttributeName
[222]    ElementName    ::=    EQName
[221]    AttributeName    ::=    EQName
[214]    PITest    ::=    "processing-instruction" "(" (NCName | StringLiteral)? ")"
[212]    CommentTest    ::=    "comment" "(" ")"
[213]    NamespaceNodeTest    ::=    "namespace-node" "(" ")"
[211]    TextTest    ::=    "text" "(" ")"
[209]    AnyKindTest    ::=    "node" "(" ")"
[225]    FunctionTest    ::=    Annotation* (AnyFunctionTest
| TypedFunctionTest)
[226]    AnyFunctionTest    ::=    "function" "(" "*" ")"
[227]    TypedFunctionTest    ::=    "function" "(" (SequenceType ("," SequenceType)*)? ")" "as" SequenceType
[241]    ParenthesizedItemType    ::=    "(" ItemType ")"
[228]    MapTest    ::=    AnyMapTest | TypedMapTest
[231]    RecordTest    ::=    "record" "(" FieldDeclaration ("," FieldDeclaration)* ExtensibleFlag? ")"
[238]    ArrayTest    ::=    AnyArrayTest | TypedArrayTest
[207]    AtomicOrUnionType    ::=    EQName
[236]    LocalUnionType    ::=    "union" "(" ItemType ("," ItemType)* ")"
[237]    EnumerationType    ::=    "enum" "(" StringLiteral ("," StringLiteral)* ")"

This section defines the semantics of different ItemTypes in terms of the values that they match.

An item type written simply as an EQName (that is, a NamedType) is interpreted as follows:

  1. If the name is written as a lexical QName, then it is expanded using the in-scope namespaces in the static context. If the name is an unprefixed NCName, then it is taken as being in the default type namespace.

  2. If the name matches an entry in the item type aliases in the static context, then it is taken as a reference to the corresponding item type. The rules that apply are the rules for the expanded item type definition.

  3. Otherwise, it must match the name of a type in the in-scope schema types in the static context: specifically, an atomic type or a plain union type. See 3.6.2 Atomic and Union Types for details.

    Note:

    A name in the xs namespace will always fall into this category, since the namespace is reserved.

  4. If the name cannot be resolved to a type, a static error is raised [err:XPST0051].

3.6.1 General item types

  • item() matches any single item.

    Example: item() matches the atomic value 1, the element <a/>, or the function fn:concat#3.

  • A ParenthesizedItemType matches an item if and only if the item matches the ItemType that is in parentheses.

    Note:

    Parenthesized item types are used primarily when defining nested item types in a function signature: for example a sequence of functions that return booleans might be denoted (function () as xs:boolean)*. In this example the parentheses are needed to indicate where the occurrence indicator belongs.

3.6.2 Atomic and Union Types

A generalized atomic type may be expressed as an ItemType in any of the following ways:

Example: The ItemType xs:decimal matches any value of type xs:decimal. It also matches any value of type shoesize, if shoesize is an atomic type derived by restriction from xs:decimal.

Example: Suppose ItemType dress-size is a union type that allows either xs:decimal values for numeric sizes (e.g. 4, 6, 10, 12), or one of an enumerated set of xs:strings (e.g. "small", "medium", "large"). The ItemType dress-size matches any of these values.

Note:

The names of list types such as xs:IDREFS are not accepted in this context, but can often be replaced by a generalized atomic type with an occurrence indicator, such as xs:IDREF+.

3.6.2.1 Local Union Types

A LocalUnionType defines an anonymous union type locally (for example, within a function signature) which may be more convenient than defining the type in an imported schema.

[236]    LocalUnionType    ::=    "union" "(" ItemType ("," ItemType)* ")"

Although the grammar allows any ItemType to appear, each ItemType must identify a generalized atomic type. [TODO: error code]

An item matches a LocalUnionType if it matches any of the generalized atomic types listed within the parentheses.

For example, the type union(xs:date, xs:dateTime, xs:time) matches any value that is an instance of xs:date, xs:dateTime, or xs:time.

Similarly, the type union(xs:NCName, enum("")) matches any value that is either an instance of xs:NCName, or a zero-length string. This might be a suitable type for a variable that holds a namespace prefix.

Note:

Local union types are particularly useful in function signatures, allowing a function to take arguments of a variety of types. The semantics are identical to using a named union type, but a local union type is more convenient because it does not need to be defined in a schema, and does not require a schema-aware processor.

A local union type can also be used in a cast expression: cast @when as union(xs:date, xs:dateTime) allows the attribute @when to be either a date, or a dateTime.

An instance of expression can be used to test whether a value belongs to one of a number of specified types: $x instance of union(xs:string, xs:anyURI, xs:untypedAtomic) returns true if $x is an instance of any of these three atomic types.

3.6.2.2 Enumeration Types

[Definition: An EnumerationType accepts a fixed set of string values.]

[237]    EnumerationType    ::=    "enum" "(" StringLiteral ("," StringLiteral)* ")"

An item matches an EnumerationType if it is an instance of xs:string, and is equal to one of the string literals listed within the parentheses, when compared using the codepoint collation.

For example, the type enum("red", "green", "blue") matches the string "green".

Note:

Unlike a schema-defined type that restricts xs:string with an enumeration facet, matching of an EnumerationType is based purely on value comparison, and not on type annotations. For example, if color is a schema-defined atomic type derived from xs:string with an enumeration facet permitting the values ("red", "green", "blue"), the expression "green" instance of color is false, because the type annotation does not match. By contrast, "green" instance of enum("red", "green", "blue") is true.

An EnumerationType only matches xs:string values, not xs:untypedAtomic or xs:anyURI values, even though these might compare equal. However, the coercion rules allow xs:untypedAtomic or xs:anyURI values to be supplied where the required type is an enumeration type.

3.6.3 Node Types

Some of the constructs described in this section include a TypeName. This appears as T in:

  • element(N, T)

  • attribute(N, T)

  • document-node(element(N, T))

In these constructs, the type name T is expanded using the in-scope namespaces in the static context, using the default type namespace if it is unprefixed. The resulting QName must identify a type in the in-scope schema definitions. This can be any schema type: either a simple type, or (except in the case of attributes) a complex type. If it is a simple type then it can be an atomic, union, or list type. It can be a built-in type (such as xs:integer) or a user-defined type. It must however be the name of a type defined in a schema; it cannot be a type alias.

3.6.3.1 Simple Node Tests
  • node() matches any node.

  • text() matches any text node.

  • processing-instruction() matches any processing-instruction node.

  • processing-instruction( N ) matches any processing-instruction node whose PITarget is equal to fn:normalize-space(N). If fn:normalize-space(N) is not in the lexical space of NCName, a type error is raised [err:XPTY0004]

    Example: processing-instruction(xml-stylesheet) matches any processing instruction whose PITarget is xml-stylesheet.

    For backward compatibility with XPath 1.0, the PITarget of a processing instruction may also be expressed as a string literal, as in this example: processing-instruction("xml-stylesheet").

    If the specified PITarget is not a syntactically valid NCName, a type error is raised [err:XPTY0004].

  • comment() matches any comment node.

  • namespace-node() matches any namespace node.

  • document-node() matches any document node.

  • document-node( E ) matches any document node that contains exactly one element node, optionally accompanied by one or more comment and processing instruction nodes, if E is an ElementTest or SchemaElementTest that matches the element node (see 3.6.3.2 Element Test and 3.6.3.3 Schema Element Test).

    Example: document-node(element(book)) matches a document node containing exactly one element node that is matched by the ElementTest element(book).

  • An ItemType that is an ElementTest, SchemaElementTest, AttributeTest, SchemaAttributeTest, or FunctionTest matches an item as described in the following sections.

3.6.3.2 Element Test
[218]    ElementTest    ::=    "element" "(" (NameTest ("," TypeName "?"?)?)? ")"
[133]    NameTest    ::=    EQName | Wildcard
[222]    ElementName    ::=    EQName
[224]    TypeName    ::=    EQName

An ElementTest is used to match an element node by its name and/or type annotation.

The ElementName and TypeName of an ElementTest have their prefixes expanded to namespace URIs by means of the statically known namespaces, or if unprefixed, the default element namespace or default type namespace respectively. The ElementName need not be present in the in-scope element declarations, but the TypeName must be present in the in-scope schema types [err:XPST0008]. Note that substitution groups do not affect the semantics of ElementTest.

An ElementTest may take any of the following forms:

  1. element() and element(*) match any single element node, regardless of its name or type annotation.

  2. element( ElementName ) matches any element node whose name is ElementName, regardless of its type annotation or nilled property.

    Example: element(person) matches any element node whose name is person.

  3. element(prefix:*) matches any element node whose name is in the namespace bound to the given prefix, regardless of its type annotation or nilled property.

    Example: element(xhtml:*) matches any element node whose name is in the namespace bound to the prefix xhtml.

  4. element(Q{uri}*) matches any element node whose name is in the namespace given as uri, regardless of its type annotation or nilled property.

    Example: element(Q{"http://www.w3.org/2000/svg"}*) matches any element node whose name is in the SVG namespace.

  5. element(*:local) matches any element node whose local name is the name given as local, regardless of its namespace, type annotation or nilled property.

    Example: element(*:html) matches any element node whose local name is "html".

  6. element( ElementName , TypeName ) matches an element node whose name is ElementName if derives-from( AT, TypeName ) is true, where AT is the type annotation of the element node, and the nilled property of the node is false.

    Example: element(person, surgeon) matches a non-nilled element node whose name is person and whose type annotation is surgeon (or is derived from surgeon).

    The ElementName in this example can also be replaced by one of the forms prefix:*, Q{uri}*, or *:local.

  7. element( ElementName, TypeName ?) matches an element node whose name is ElementName if derives-from( AT, TypeName ) is true, where AT is the type annotation of the element node. The nilled property of the node may be either true or false.

    Example: element(person, surgeon?) matches a nilled or non-nilled element node whose name is person and whose type annotation is surgeon (or is derived from surgeon).

    The ElementName in this example can also be replaced by one of the forms prefix:*, Q{uri}*, or *:local.

  8. element(*, TypeName ) matches an element node regardless of its name, if derives-from( AT, TypeName ) is true, where AT is the type annotation of the element node, and the nilled property of the node is false.

    Example: element(*, surgeon) matches any non-nilled element node whose type annotation is surgeon (or is derived from surgeon), regardless of its name.

  9. element(*, TypeName ?) matches an element node regardless of its name, if derives-from( AT, TypeName ) is true, where AT is the type annotation of the element node. The nilled property of the node may be either true or false.

    Example: element(*, surgeon?) matches any nilled or non-nilled element node whose type annotation is surgeon (or is derived from surgeon), regardless of its name.

3.6.3.3 Schema Element Test
[219]    SchemaElementTest    ::=    "schema-element" "(" ElementDeclaration ")"
[220]    ElementDeclaration    ::=    ElementName
[222]    ElementName    ::=    EQName

A SchemaElementTest matches an element node against a corresponding element declaration found in the in-scope element declarations.

The ElementName of a SchemaElementTest has its prefixes expanded to a namespace URI by means of the statically known namespaces, or if unprefixed, the default element namespace . If the ElementName specified in the SchemaElementTest is not found in the in-scope element declarations, a static error is raised [err:XPST0008].

A SchemaElementTest matches a candidate element node if all of the following conditions are satisfied:

  1. Either:

    1. The name N of the candidate node matches the specified ElementName, or

    2. The name N of the candidate node matches the name of an element declaration that is a member of the actual substitution group headed by the declaration of element ElementName.

    Note:

    The term "actual substitution group" is defined in [XML Schema 1.1]. The actual substitution group of an element declaration H includes those element declarations P that are declared to have H as their direct or indirect substitution group head, provided that P is not declared as abstract, and that P is validly substitutable for H, which means that there must be no blocking constraints that prevent substitution.

  2. The schema element declaration named N is not abstract.

  3. derives-from( AT, ET ) is true, where AT is the type annotation of the candidate node and ET is the schema type declared in the schema element declaration named N.

  4. If the schema element declaration named N is not nillable, then the nilled property of the candidate node is false.

Example: The SchemaElementTest schema-element(customer) matches a candidate element node in the following two situations:

  1. customer is a top-level element declaration in the in-scope element declarations; the name of the candidate node is customer; the element declaration of customer is not abstract; the type annotation of the candidate node is the same as or derived from the schema type declared in the customer element declaration; and either the candidate node is not nilled, or customer is declared to be nillable.

  2. customer is a top-level element declaration in the in-scope element declarations; the name of the candidate node is client; client is an actual (non-abstract and non-blocked) member of the substitution group of customer; the type annotation of the candidate node is the same as or derived from the schema type declared for the client element; and either the candidate node is not nilled, or client is declared to be nillable.

3.6.3.4 Attribute Test
[215]    AttributeTest    ::=    "attribute" "(" (NameTest ("," TypeName)?)? ")"
[133]    NameTest    ::=    EQName | Wildcard
[221]    AttributeName    ::=    EQName
[224]    TypeName    ::=    EQName

An AttributeTest is used to match an attribute node by its name and/or type annotation.

The AttributeName and TypeName of an AttributeTest have their prefixes expanded to namespace URIs by means of the statically known namespaces. If unprefixed, the AttributeName is in no namespace, but an unprefixed TypeName is in the default type namespace . The AttributeName need not be present in the in-scope attribute declarations, but the TypeName must be present in the in-scope schema types [err:XPST0008].

An AttributeTest may take any of the following forms:

  1. attribute() and attribute(*) match any single attribute node, regardless of its name or type annotation.

  2. attribute( AttributeName ) matches any attribute node whose name is AttributeName, regardless of its type annotation.

    Example: attribute(price) matches any attribute node whose name is price.

  3. attribute(prefix:*) matches any attribute node whose name is in the namespace bound to the given prefix, regardless of its type annotation.

    Example: attribute(xlink:*) matches any attribute node whose name is in the namespace bound to the prefix xlink.

  4. attribute(Q{uri}*) matches any attribute node whose name is in the namespace given as uri, regardless of its type annotation.

    Example: element(Q{"http://www.w3.org/2000/svg"}*) matches any attribute node whose name is in the SVG namespace.

  5. attribute(*:local) matches any attribute node whose local name is the name given as local, regardless of its namespace or type annotation.

    Example: attribute(*:default-collation) matches any attribute node whose local name is "default-collation".

  6. attribute( AttributeName, TypeName ) matches an attribute node whose name is AttributeName if derives-from( AT, TypeName ) is true, where AT is the type annotation of the attribute node.

    Example: attribute(price, currency) matches an attribute node whose name is price and whose type annotation is currency (or is derived from currency).

    The AttributeName in this example can also be replaced by one of the forms prefix:*, Q{uri}*, or *:local.

  7. attribute(*, TypeName ) matches an attribute node regardless of its name, if derives-from( AT, TypeName ) is true, where AT is the type annotation of the attribute node.

    Example: attribute(*, currency) matches any attribute node whose type annotation is currency (or is derived from currency), regardless of its name.

3.6.3.5 Schema Attribute Test
[216]    SchemaAttributeTest    ::=    "schema-attribute" "(" AttributeDeclaration ")"
[217]    AttributeDeclaration    ::=    AttributeName
[221]    AttributeName    ::=    EQName

A SchemaAttributeTest matches an attribute node against a corresponding attribute declaration found in the in-scope attribute declarations.

The AttributeName of a SchemaAttributeTest has its prefixes expanded to a namespace URI by means of the statically known namespaces. If unprefixed, an AttributeName is in no namespace. If the AttributeName specified in the SchemaAttributeTest is not found in the in-scope attribute declarations, a static error is raised [err:XPST0008].

A SchemaAttributeTest matches a candidate attribute node if both of the following conditions are satisfied:

  1. The name of the candidate node matches the specified AttributeName.

  2. derives-from( AT, ET ) is true, where AT is the type annotation of the candidate node and ET is the schema type declared for attribute AttributeName in the in-scope attribute declarations.

Example: The SchemaAttributeTest schema-attribute(color) matches a candidate attribute node if color is a top-level attribute declaration in the in-scope attribute declarations, the name of the candidate node is color, and the type annotation of the candidate node is the same as or derived from the schema type declared for the color attribute.

3.6.4 Function, Map, and Array Tests

The following sections describe the syntax for item types for function, including arrays and maps.

The subtype relation among these types is described in the various subsections of 3.7.2 Subtypes of Item Types.

3.6.4.1 Function Test
[225]    FunctionTest    ::=    Annotation* (AnyFunctionTest
| TypedFunctionTest)
[226]    AnyFunctionTest    ::=    "function" "(" "*" ")"
[227]    TypedFunctionTest    ::=    "function" "(" (SequenceType ("," SequenceType)*)? ")" "as" SequenceType

A FunctionTest matches a function item, potentially also checking its function signatureDM31 and annotations (see 5.15 Annotations). An AnyFunctionTest matches any item that is a function. A TypedFunctionTest matches an item if it is a function and the function's type signature (as defined in Section 2.8.1 Functions DM31) is a subtype of the TypedFunctionTest.

Here are some examples of FunctionTests:

  1. function(*) matches any function, including maps and arrays.

  2. %assertion function(*) matches any function if the implementation-defined function assertion %assertion is satisfied.

  3. function(int, int) as int matches any function item with the function signature function(int, int) as int.

  4. %assertion function(int, int) as int matches any function item with the function signature function(int, int) as int if the implementation-defined function assertion %assertion is satisfied.

  5. function(xs:anyAtomicType) as item()* matches any map, or any function with the required signature.

  6. function(xs:integer) as item()* matches any array, or any function with the required signature.

[Definition: A function assertion is a predicate that restricts the set of functions matched by a FunctionTest. It uses the same syntax as 5.15 Annotations.] XQuery 4.0 does not currently define any function assertions, but future versions may. Other specifications in the XQuery family may also use function assertions in the future.

Implementations are free to define their own function assertions, whose behavior is completely implementation-defined. Implementations may also provide a way for users to define their own function assertions.

An implementation may raise implementation-defined errors or warnings for function assertions, e.g. if the parameters are not correct for a given assertion. If the namespace URI of a function assertion's expanded QName is not recognized by an implementation, it is ignored, and has no effect on the semantics of the function test.

Note:

An implementation is free to raise warnings for function assertions that it does not recognize.

Note:

Although function assertions use the same syntax as annotations, they are not directly related to annotations. If an implementation defines the annotation blue and uses it in function declarations, there is no guarantee that it will also define a function assertion blue, or that a function assertion named blue matches a function declared with the annotation blue. Of course, an implementation that does so may be more intuitive to users.

Implementations must not define function assertions in reserved namespaces; it is is a static error [err:XQST0045] for a user to define a function assertion in a reserved namespace.

3.6.4.2 Map Test
[228]    MapTest    ::=    AnyMapTest | TypedMapTest
[229]    AnyMapTest    ::=    "map" "(" "*" ")"
[230]    TypedMapTest    ::=    "map" "(" ItemType "," SequenceType ")"

The MapTest map(*) matches any map. The MapTest map(X, Y) matches any map where the type of every key is an instance of X and the type of every value is an instance of Y.

Although the grammar for TypedMapTest allows the key to be described using the full ItemType syntax, the item type used must be a generalized atomic type. [TODO: error code].

Examples:

Given a map $M whose keys are integers and whose results are strings, such as map{0:"no", 1:"yes"}, consider the results of the following expressions:

  • $M instance of map(*) returns true()

  • $M instance of map(xs:integer, xs:string) returns true()

  • $M instance of map(xs:decimal, xs:anyAtomicType) returns true()

  • not($M instance of map(xs:int, xs:string)) returns true()

  • not($M instance of map(xs:integer, xs:token)) returns true()

Because of the rules for subtyping of function types according to their signature, it follows that the item type function(A) as item()*, where A is an atomic type, also matches any map, regardless of the type of the keys actually found in the map. For example, a map whose keys are all strings can be supplied where the required type is function(xs:integer) as item()*; a call on the map that treats it as a function with an integer argument will always succeed, and will always return an empty sequence.

The function signature of a map matching type map(K, V), treated as a function, is function(xs:anyAtomicType) as V?. It is thus always a subtype of function(xs:anyAtomicType) as item()* regardless of the actual types of the keys and values in the map. The rules for function coercion mean that any map can be supplied as a value in a context where the required type has a more specific return type, such as function(xs:anyAtomicType) as xs:integer, even when the map does not match in the sense required to satisfy the instance of operator. In such cases, a type error will only occur if an actual call on the map (treated as a function) returns a value that is not an instance of the required return type.

Examples:

  • $M instance of function(*) returns true()

  • $M instance of function(xs:anyAtomicType) as item()* returns true()

  • $M instance of function(xs:integer) as item()* returns true()

  • $M instance of function(xs:int) as item()* returns true()

  • $M instance of function(xs:string) as item()* returns true()

  • not($M instance of function(xs:integer) as xs:string) returns true()

Note:

The last case might seem surprising; however, function coercionn ensures that $M can be used successfully anywhere that the required type is function(xs:integer) as xs:string.

Rules defining whether one map type is a subtype of another are given in 3.7.2.7 Maps.

3.6.4.3 Record Test
[231]    RecordTest    ::=    "record" "(" FieldDeclaration ("," FieldDeclaration)* ExtensibleFlag? ")"
[232]    FieldDeclaration    ::=    FieldName "?"? ("as" (SequenceType | SelfReference))?
[233]    FieldName    ::=    NCName | StringLiteral
[234]    SelfReference    ::=    ".." OccurrenceIndicator?
[235]    ExtensibleFlag    ::=    "," "*"

A RecordTest matches maps that meet specific criteria.

For example, the RecordTest record(r as xs:double, i as xs:double) matches a map if the map has exactly two entries: an entry with key "r" whose value is a singleton xs:double value, and an entry with key "i" whose value is also a singleton xs:double value.

If the list of fields ends with ",*" then the record test is said to be extensible. For example, the RecordTest record(e as element(Employee), *) matches a map if it has an entry with key "e" whose value matches element(Employee), regardless what other entries the map might contain.

A record test can only constrain entries whose keys are strings, but when the record test is marked as extensible, then other entries may be present in the map with non-string keys. Entries whose key is a string can be expressed using an (unquoted) NCName if the key conforms to NCName syntax, or using a (quoted) string literal otherwise.

Note:

Lookup expressions have been extended so that non-NCName keys can be used without parentheses: employee?"middle name"

If the type declaration for a field is omitted, then item()* is assumed: that is, the map entry may have any type.

If the field name is followed by a question mark, then the value must have the specified type if it is present, but it may also be absent. For example, the RecordTest record(first as xs:string, middle? as xs:string, last as xs:string, *) requires the map to have string-valued entries with keys "first" and "last"; it also declares that if the map has an entry with key "middle", the value of that entry must be a single xs:string. Declaring the type as record(first as xs:string, middle? as xs:string?, last as xs:string, *) also allows the entry with key "middle" to be present but empty.

Note:

Within an extensible record test, a FieldDeclaration that is marked optional and has no declared type does not constrain the map in any way, so it serves no practical purpose, but it is permitted because it may have documentary value.

If a field is declared using .. (optionally followed by an occurrence indicator) in place of a SequenceType, this indicates that the record type is recursive: the value of this field, if present, must be an instance of the record type being declared. For example, a record designed to hold error information might be declared as:

record(error-code as xs:QName, message as xs:string, cause? as ..)

A map conforms to this type if it has entries with keys error-code and message of the correct types, and if the cause entry is either absent, or is a map that itself conforms to this type.

A FieldDeclaration that a SelfReference to identify its type must either be optional (marked with a question mark after the name), or must allow the empty sequence as a permitted value (marked by using the occurrence indicator ? or * after the item type). If the field is not optional and does not allow an empty sequence, a static error is raised [err:XPST0140]. This rule ensures that finite instances of the type can be constructed.

A record used to represent a node in a binary tree might be represented as:

record(left? as .., value, right? as ..)

A function to walk this tree and enumerate all the values in depth-first order might be written (using XQuery syntax) as:

declare item-type binary-tree as
    record(left? as .., value, right? as ..);                 
declare function flatten($tree as binary-tree?) as item()* {
    $tree ! (flatten(?left), ?value, flatten(?right))   
}

 

A record used to represent a node in a tree where each node has an arbitrary number of children might be represented as:

record(value, children as ..*)

A function to walk this tree and enumerate all the values in order might be written (using XQuery syntax) as:

declare item-type tree as
    record(value, children as ..*);                 
declare function flatten($tree as tree) as item()* {
    $tree?value, $tree?children ! flatten(.))   
}

Note:

If a RecordTest contains a SelfReference field that is not optional, and whose type does not permit an empty sequence, then it will not be possible to construct an instance. So a RecordTest such as record(a as ..) serves no practical purpose; but it is not disallowed.

Record tests describe a subset of the value space of maps. They do not define any new kinds of values, or any additional operations. They are useful in many cases to describe more accurately the type of a variable, function parameter, or function result, giving benefits both in the readability of the code, and in the ability of the processor to detect and diagnose type errors and to optimize execution.

In particular, if a variable $rec is known to conform to a particular record type, then when a lookup expression $rec?field is used, (a) the processor can report a type error if $rec cannot contain an entry with name field, and (b) the processor can make static type inferences about the type of value returned by $rec?field.

Note:

A number of functions in the standard function library use maps as function arguments; this is a useful technique where the information to be supplied across the interface is highly variable. However, the type signature for such functions typically declares the argument type as map(*), which gives very little information (and places very few constraints) on the values that are actually passed across. Using record tests offers the possibility of improving this: for example, the options argument of fn:parse-json, previously given as map(*), can now be expressed as record(liberal? as xs:boolean, duplicates? as xs:string, escape? as xs:boolean, fallback as function(xs:string) as xs:string, *). In principle the xs:string type used to describe the duplicates option could also be replaced by a schema-defined subtype of xs:string that enumerates the permitted values ("reject", "use-first", "use-last").

The use of a record test in the signature of such a function causes the coercion rules to be invoked: so, for example, if the function expects an entry in the map to be an xs:double value, it becomes possible to supply a map in which the corresponding entry has type xs:integer.

Greater precision in defining the types of such arguments also enables better type checking, better diagnostics, better optimization, better documentation, and better syntax-directed editing tools.

Note:

One of the motivations for introducing record tests is to enable better pattern matching in XSLT when processing JSON input. With XML input, patterns are often based around XML element names. JSON has no direct equivalent of XML's element names; matching a JSON object such as {longitude: 130.2, latitude: 53.4} relies instead on recognizing the property names appearing in the object. XSLT 4.0, by integrating record tests into pattern matching syntax, allows such an object to be matched with a pattern of the form match="record(longitude, latitude)"

Rules defining whether one record type is a subtype of another are given in 3.7.2.9 Record Tests.

3.6.4.4 Array Test
[238]    ArrayTest    ::=    AnyArrayTest | TypedArrayTest
[239]    AnyArrayTest    ::=    "array" "(" "*" ")"
[240]    TypedArrayTest    ::=    "array" "(" SequenceType ")"

The AnyArrayTest array(*) matches any array. The TypedArrayTest array(X) matches any array in which every array member matches the SequenceType X.

Examples:

  • [ 1, 2 ] instance array(*) returns true()

  • [] instance of array(xs:string) returns true()

  • [ "foo" ] instance of array(xs:string) returns true()

  • [ "foo" ] instance of array(xs:integer) returns false()

  • [(1,2),(3,4)] instance of array(xs:integer) returns false()

  • [(1,2),(3,4)] instance of array(xs:integer+) returns true()

An array also matches certain other ItemTypes, including:

  • item()

  • function(*)

  • function(xs:integer) as item()*

The function signature of an array matching array(X), treated as a function, is function(xs:integer) as X. It is thus always a subtype of function(xs:integer) as item()* regardless of the actual member types in the array. The rules for function coercion mean that any array can be supplied as a value in a context where the required type has a more specific return type, such as function(xs:integer) as xs:integer, even when the array does not match in the sense required to satisfy the instance of operator. In such cases, a type error will only occur if an actual call on the array (treated as a function) returns a value that is not an instance of the required return type.

Rules defining whether one array type is a subtype of another are given in 3.7.2.8 Arrays.

3.6.5 xs:error

The type xs:error has an empty value space; it never appears as a dynamic type or as the content type of a dynamic element or attribute type. It was defined in XML Schema in the interests of making the type system complete and closed, and it is also available in XQuery 4.0 for similar reasons.

Note:

Even though it cannot occur in an instance, xs:error is a valid type name in a sequence type. The practical uses of xs:error as a sequence type are limited, but they do exist. For instance, an error handling function that always raises a dynamic error never returns a value, so xs:error is a good choice for the return type of the function.

The semantics of xs:error are well-defined as a consequence of the fact that xs:error is defined as a union type with no member types. For example:

  • $x instance of xs:error always returns false, regardless of the value of $x.

  • $x cast as xs:error fails dynamically with error [err:FORG0001]FO31, regardless of the value of $x.

  • $x cast as xs:error? raises a dynamic error [err:FORG0001]FO31 if exists($x), evaluates to the empty sequence if empty($x).

  • xs:error($x) has the same semantics as $x cast as xs:error? (see the previous bullet point)

  • $x castable as xs:error evaluates to false, regardless of the value of $x.

  • $x treat as xs:error raises a dynamic error [err:XPDY0050] if evaluated, regardless of the value of $x. It never fails statically.

  • let $x as xs:error := 1 return 2 raises a type error [err:XPTY0004], which can be raised statically or dynamically, and need not be raised if the variable $x is never evaluated by the query processor.

  • declare function ns:f($arg as xs:error) {...}; is a valid function declaration, but it always raises a type error [err:XPTY0004] if the function is called.

All of the above examples assume that $x is actually evaluated. If the result of the query does not depend on the value of $x. the rules specified in 2.4.4 Errors and Optimization permit an implementation to avoid evaluating $x and thus to avoid raising an error.

3.7 Subtype Relationships

[Definition: Given two sequence types or item types, the rules in this section determine if one is a subtype of the other. If a type A is a subtype of type B, it follows that every value matched by A is also matched by B.]

Note:

The relationship subtype(A, A) is always true: every type is a subtype of itself.

Note:

The converse is not necessarily true: we cannot infer that if every value matched by A is also matched by B, then A is a subtype of type B. For example, A might be defined as the set of strings matching the regular expression [A-Z]*, while B is the set of strings matching the regular expression [A-Za-z]*; no subtype relationship holds between these types.

The rules for deciding whether one sequence type is a subtype of another are given in 3.7.1 Subtypes of Sequence Types. The rules for deciding whether one item type is a subtype of another are given in 3.7.2 Subtypes of Item Types.

Note:

The subtype relationship is not acyclic. There are cases where subtype(A, B) and subtype(B, A) are both true. This implies that A and B have the same value space, but they can still be different types. For example this applies when A is a union type with member types xs:string and xs:integer, while B is a union type with member types xs:integer and xs:string. These are different types ("23" cast as A produces a string, while "23" cast as B produces an integer, because casting is attempted to each member type in order) but both types have the same value space.

3.7.1 Subtypes of Sequence Types

We use the notation A ⊑ B, or subtype(A, B) to indicate that a sequence type A is a subtype of a sequence type B. This section defines the rules for deciding whether any two sequence types have this relationship.

To define the rules, we divide sequence types into six categories:

  • The category empty includes the sequence types empty-sequence(), xs:error* and xs:error?. All these sequence types match the empty sequence as their only instance.

  • The category void includes the sequence types xs:error and xs:error+, which have no instances (not even the empty sequence).

  • The categories X?, X*, X and X+ includes all sequence types having an item type X other than xs:error, together with an occurrence indicator of ? (zero or more), * (one or more), absent (exactly one), or + (one or more) respectively. We use the notation Xi to indicate the item type of such a sequence type.

The judgement A ⊑ B is then determined by the categories of the two sequence types, as defined in the table below. In many cases this depends on the relationship between the item types of A and B. This is denoted using the notation AiBi , as defined in 3.7.2 Subtypes of Item Types.

Sequence type B
empty Bi? Bi* Bi Bi+ void
Sequence type A empty true true true false false false
Ai? false AiBi AiBi false false false
Ai* false false AiBi false false false
Ai false AiBi AiBi AiBi AiBi false
Ai+ false false AiBi false AiBi false
void true true true true true true

3.7.2 Subtypes of Item Types

We use the notation A ⊆ B, or itemtype-subtype(A, B) to indicate that an item type A is a subtype of an item type B. This section defines the rules for deciding whether any two item types have this relationship.

Before applying these rules, any ItemType written as item-type(N) is replaced with the definition of the named item type N, recursively. The rules are written in terms of the lexical form of the two item types, but it is assumed that trivial variations are first eliminated: comments and unnecessary whitespace are removed, lexical QNames are replaced by URI-qualified names applying appropriate defaults in the case of unprefixed names, equivalent forms such as element() and element(*) are normalized.

The relationship A ⊆ B is true if and only if at least one of the conditions listed in the following subsections applies:

3.7.2.1 General Rules

Given item types A and B, A B is true if any of the following apply:

  1. A is xs:error.

  2. B is item().

  3. A and B are the same item type.

  4. There is an item type X such that AX and XB . (This is referred to below as the transitivity rule).

Note:

The first rule is technically redundant: it is implied by the second rule in 3.7.2.2 Atomic and Union Types. The type xs:error is defined as a union type with no member types; therefore it is automatically true that every member type T satisfies TB .

3.7.2.2 Atomic and Union Types

Given item types A and B, A B is true if any of the following apply:

  1. A and B are generalized atomic types, and derives-from(A, B) returns true.

    The derives-from relationship is defined in 3.5 Sequence Type Matching.

    Examples:
    • xs:integer ⊆ xs:decimal because xs:integer is derived by restriction from xs:decimal.

    • xs:decimal ⊆ xs:numeric because xs:numeric is a pure union type that includes xs:decimal as a member type.

  2. A is a pure union type, and every type T in the transitive membership of A satisfies TB .

    Examples:
    • union(xs:short, xs:long) ⊆ xs:integer because xs:short ⊆ xs:integer and xs:long ⊆ xs:integer.

    • union(P, Q) ⊆ union(P, Q, R) because P ⊆ union(P, Q, R) and Q ⊆ union(P, Q, R).

    Note:

    This rule applies both when A is a schema-defined union type and when it is a LocalUnionType.

  3. A is an EnumerationType, and B matches every string literal in the enumeration of A.

    Examples:
    • enum("red", "green", "blue") ⊆ xs:string

    • enum("red", "green", "blue") ⊆ enum("red", "green", "blue", "yellow")

3.7.2.3 Node Types: General Rules

Given item types A and B, A B is true if any of the following apply:

  1. A is a KindTest and B is node().

    Example:

    comment() ⊆ node()

  2. A is processing-instruction(N) for any name N, and B is processing-instruction().

    Example:

    processing-instruction('pi') ⊆ processing-instruction()

  3. A is document-node(E) for any ElementTest E, and B is document-node().

    Example:

    document-node(element(chap)) ⊆ document-node()

  4. All the following are true:

    1. A is document-node(Ae)

    2. B is document-node(Be)

    3. AeBe

    Example:

    document-node(element(title)) ⊆ document-node(element(*)).

3.7.2.4 Node Types: Element Tests

[Definition: In these rules, if M and N are NameTests, then M wildcard-matches N is true if every name that matches M also matches N.] More specifically, this is the case if any of the following apply:

  1. M and N are the same NameTest.

  2. M is an EQName and N is a Wildcard that matches M.

  3. N is the Wildcard *.

Given item types A and B, A B is true if any of the following apply.

  1. A is an ElementTest and B is either element() or element(*)

  2. All the following are true:

    1. A is either element(An) or element(An, T) or element(An, T?) for any type T

    2. B is either element(Bn) or element(Bn, xs:anyType?)

    3. An wildcard-matches Bn

    Examples:
    • element(title) ⊆ element(*)

    • element(title, xs:string) ⊆ element(*)

    • element(title, xs:string?) ⊆ element(*)

    • element(title) ⊆ element(title, xs:anyType?)

    • element(title, xs:integer) ⊆ element(title, xs:anyType?)

    • element(title, xs:string?) ⊆ element(title, xs:anyType?)

    • element(my:title) ⊆ element(*:title)

    • element(my:title) ⊆ element(my:*)

  3. All the following are true:

    1. A is element(An, At)

    2. B is element(Bn, Bt)

    3. An wildcard-matches Bn

    4. derives-from(At, Bt).

    Examples:
    • element(size, xs:integer) ⊆ element(size, xs:decimal)

    • element(size, xs:integer) ⊆ element(*, xs:decimal)

    • element(*, xs:integer) ⊆ element(*, xs:decimal)

    • element(my:*, xs:integer) ⊆ element(*, xs:decimal)

  4. All the following are true:

    1. A is either element(An, At) or element(An, At?)

    2. B is element(Bn, Bt?)

    3. An wildcard-matches Bn

    4. derives-from(At, Bt).

    Examples:
    • element(size, xs:integer) ⊆ element(size, xs:decimal?)

    • element(size, xs:integer?) ⊆ element(*, xs:decimal?)

    • element(*, xs:integer) ⊆ element(*, xs:decimal?)

    • element(my:*, xs:integer?) ⊆ element(*, xs:decimal?)

  5. All the following are true:

    1. A is schema-element(An)

    2. B is schema-element(Bn)

    3. Every element declaration that is an actual member of the substitution group of An is also an actual member of the substitution group of Bn.

    Note:

    The fact that P is a member of the substitution group of Q does not mean that every element declaration in the substitution group of P is also in the substitution group of Q. For example, Q might block substitution of elements whose type is derived by extension, while P does not.

3.7.2.5 Node Types: Attribute Tests

Given item types A and B, A B is true if any of the following apply:

  1. A is an AttributeTest and B is either attribute() or attribute(*)

  2. All the following are true:

    1. A is either attribute(An) or attribute(An, T) for any type T.

    2. B is either attribute(Bn) or attribute(Bn, xs:anyAtomicType)

    3. An wildcard-matches Bn

    Examples:
    • attribute(code) ⊆ attribute(*)

    • attribute(code, xs:untypedAtomic) ⊆ attribute(*)

    • attribute(code, xs:string) ⊆ attribute(code, xs:anyAtomicType)

    • attribute(my:code) ⊆ attribute(*:code)

    • attribute(my:code) ⊆ attribute(my:*)

  3. All the following are true:

    1. A is attribute(An, At)

    2. B is attribute(Bn, Bt)

    3. An wildcard-matches Bn

    4. derives-from(At, Bt).

    Examples:
    • attribute(*, xs:ID) ⊆ attribute(*, xs:string)

    • attribute(my:*, xs:ID) ⊆ attribute(*, xs:string)

    • attribute(code, xs:ID) ⊆ attribute(code, xs:string)

    • attribute(code, xs:ID) ⊆ attribute(*, xs:string)

    • attribute(code, xs:ID) ⊆ attribute(*:code, xs:ID)

    • attribute(my:code, xs:ID) ⊆ attribute(my:*, xs:string)

  4. All the following are true:

    1. A is schema-attribute(An)

    2. B is schema-attribute(Bn)

    3. the expanded QName of An equals the expanded QName of Bn

3.7.2.6 Functions

Given item types A and B, A B is true if any of the following apply:

  1. All the following are true:

    1. A is a FunctionTest with annotations [AnnotationsA]

    2. B is [AnnotationsB] function(*)

    3. subtype-assertions(AnnotationsA, AnnotationsB), where [AnnotationsB] and [AnnotationsA] are optional lists of one or more annotations.

    Example:

    function(xs:integer) as xs:string ⊆ function(*)

  2. All the following are true:

    1. A is AnnotationsA function(a1, a2, ... aM) as RA

    2. B is AnnotationsB function(b1, b2, ... bN) as RB

    3. [AnnotationsB] and [AnnotationsA] are optional lists of one or more annotations;

    4. N (the arity of B) equals M (the arity of A)

    5. RARB

    6. For all values of p between 1 and N, bpap , and subtype-assertions(AnnotationsA, AnnotationsB)

    Examples:
    • function(xs:integer) as xs:string ⊆ function(xs:long) as xs:string

    • function(xs:integer) as xs:ID ⊆ function(xs:integer) as xs:string

    • function(xs:integer) as xs:ID ⊆ function(xs:long) as xs:string

    Note:

    Function return types are covariant because this rule requires RARB for return types. Function parameter types are contravariant because this rule requires bpap for parameter types.

3.7.2.7 Maps

Given item types A and B, A B is true if any of the following apply:

  1. Both of the following are true:

    1. A is map(K, V), for any K and V

    2. B is map(*)

    Example:

    map(xs:integer, item()*) ⊆ map(*)

  2. All the following are true:

    1. A is map(Ka, Va)

    2. B is map(Kb, Vb)

    3. KaKb

    4. VaVb

    Example:

    map(xs:long, item()) ⊆ map(xs:integer, item()+)

  3. Both the following are true:

    1. A is map(*) (or, because of the transitivity rules, any other map type)

    2. B is function(*)

    Example:

    map(xs:long, xs:string?) ⊆ function(*)

  4. Both the following are true:

    1. A is map(*) (or, because of the transitivity rules, any other map type)

    2. B is function(xs:anyAtomicType) as item()*

    Example:

    map(xs:long, xs:string?) ⊆ function(xs:anyAtomicType) as item()*

  5. Both the following are true:

    1. A is map(K, V)

    2. B is function(xs:anyAtomicType) as W , where W has the same item type as V, but also allows an empty sequence.

    Examples:
    • map(xs:int, node()) ⊆ function(xs:anyAtomicType) as node()?

    • map(xs:int, node()+) ⊆ function(xs:anyAtomicType) as node()*

    The function accepts type xs:anyAtomicType rather than xs:int, because $M("xyz") is a valid call on a map (treated as a function) even when all the keys in the map are integers.

    The return type of the function is extended from node() or node()+ to allow an empty sequence because $M("xyz") can return an empty sequence even if none of the entries in the map contains an empty sequence.

3.7.2.8 Arrays

Given item types A and B, A B is true if any of the following apply:

  1. Both the following are true:

    1. A is array(X)

    2. B is array(*)

    Example:

    array(xs:integer) ⊆ array(*)

  2. All the following are true:

    1. A is array(X)

    2. B is array(Y)

    3. XY

    Example:

    array(xs:integer) ⊆ array(xs:decimal+)

  3. Both the following are true:

    1. A is array(*) (or, because of the transitivity rules, any other array type)

    2. B is function(*)

    Example:

    array(xs:integer) ⊆ function(*)

  4. Both the following are true:

    1. A is array(*) (or, because of the transitivity rules, any other array type)

    2. B is function(xs:integer) as item()*

    Example:

    array(*) ⊆ function(xs:integer) as item()*

  5. Both the following are true:

    1. A is array(X)

    2. B is function(xs:integer) as X

    Example:

    array(xs:string) ⊆ function(xs:integer) as xs:string

3.7.2.9 Record Tests

Given item types A and B, A B is true if any of the following apply:

  1. All of the following are true:

    1. A is a record test

    2. B is map(*)

    Example:

    record(longitude, latitude)map(*)

  2. All of the following are true:

    1. A is a non-extensible record test

    2. B is map(K, V)

    3. K is either xs:string or xs:anyAtomicType

    4. For every field F in A, where T is the declared type of F (or its default, item()*), TV .

    Examples:
    • record(x, y)map(xs:string, item()*)

    • record(x as xs:double, y as xs:double)map(xs:string, xs:double)

  3. All of the following are true:

    1. A is a non-extensible record test.

    2. B is a non-extensible record test.

    3. Every field in A is also declared in B.

    4. Every mandatory field in B is also declared in A.

    5. For every field that is declared in both A and B, where the declared type in A is T and the declared type in B is U, TU .

    Examples:
    • record(x, y as xs:integer) ⊆ record(x, y as xs:decimal)

    • record(x, y) ⊆ record(x, y, z?)

  4. All of the following are true:

    1. A is an extensible record test

    2. B is an extensible record test

    3. Every mandatory field in B is also declared in A.

    4. For every field that is declared in both A and B, where the declared type in A is T and the declared type in B is U, TU .

    5. For every field that is declared in B but not in A, the declared type in B is item()*.

    Examples:
    • record(x, y, z, *) ⊆ record(x, y, *)

    • record(x?, y?, z?, *) ⊆ record(x, y, *)

    • record(x as xs:integer, y as xs:integer, *) ⊆ record(x as xs:decimal, y as xs:integer*, *)

    • record(x as xs:integer, *) ⊆ record(x as xs:decimal, y as item(), *)

  5. All of the following are true:

    1. A is a non-extensible record test.

    2. B is an extensible record test.

    3. Every mandatory field in B is also declared in A.

    4. Every field that is declared in B with a type other than item()* is also declared in A.

    5. For every field that is declared in both A and B, where the declared type in A is T and the declared type in B is U, TU .

    Examples:
    • record(x, y as xs:integer) ⊆ record(x, y as xs:decimal, *)

    • record(y as xs:integer) ⊆ record(x?, y as xs:decimal, *)

3.7.3 The judgement subtype-assertions(AnnotationsA, AnnotationsB)

The judgement subtype-assertions(AnnotationsA, AnnotationsB) determines if AnnotationsA is a subtype of AnnotationsB, where AnnotationsA and AnnotationsB are annotation lists from two FunctionTests. It is defined to ignore function assertions in namespaces not understood by the XQuery implementation. For assertions that are understood, their effect on the result of subtype-assertions() is implementation defined.

The following examples are some possible ways to define subtype-assertions() for some implementation defined assertions in the local namespace. These examples assume that some implementation uses annotations to label functions as deterministic or nondeterministic, and treats deterministic functions as a subset of nondeterministic functions. In this implementation, nondeterministic functions are not a subset of deterministic functions.

  • AnnotationsA is

    %local:inline

    It has no influence on the outcome of subtype-assertions().

  • AnnotationsA is

    %local:deterministic

    AnnotationsB is

    %local:nondeterministic

    Since deterministic functions are a subset of nondeterministic functions, subtype-assertions() is true.

  • AnnotationsA contains

    %local:nondeterministic

    AnnotationsB is empty. If FunctionTests without the %local:nondeterministic annotation only match deterministic functions, subtype-assertions() must be false.