Union types
A construct of the form union(type1, type2, type3)
can be used to define simple
unions of atomic types. For example, union(xs:base64Binary, xs:hexBinary)
defines a union type whose members are xs:base64Binary
and xs:hexBinary
, while
union(xs:date, xs:time, xs:dateTime)
defines a union type whose members are xs:date
,
xs:time
, and xs:dateTime
. These types can conveniently be used in function signatures
when writing a function that is designed to take arguments of more than one type.
The names between the parentheses are strictly QNames (not general ItemTypes) and must refer to named atomic or union types. If one of the members is a union type then it must be a "generalized atomic type" in the sense of the XPath 3.1 specification: that is, it must not contain any list types, and must not be derived by restriction from another union type.
The order of member type names is significant, in that it determines the order used for casting or validating strings.
This construct can be used anywhere that a conventional union
type name defined in a schema would be recognized, for example in instance of
and cast as
expressions, in the as
attribute of variable and function declarations, or in typeswitch
expressions. The semantics are exactly the same as if the union type were declared in an imported schema and
referenced by name. However, it does not require the processor to be schema-aware.
Union types can also be used in XSLT match patterns, for example a template defined with
match="union(xs:date, xs:time)"
will match atomic values of those types.
Such a pattern is allocated a default priority designed to reflect the type hierarchy,
so if U is a subtype of V, then the pattern corresponding to U will have a higher priority
than the pattern corresponding to V. However, the algorithm does not ensure that ambiguous
union patterns have the same priority, so ambiguities may go undetected.
The pattern match="atomic(xs:date)"
works in the same way; it can be
regarded as syntactic sugar for a union with only one member.
Two additional Saxon extensions help to improve the usability of union types:
- A commonly used type can be referenced using a type alias, for example
as="type(my:date-or-time)"
. Type aliases are available in both XSLT and XQuery, and are described in Type aliases. Type aliases go some way towards hiding the implementation details of the type, and allowing the implementation to be changed without affecting users of the function library; in addition they simply make the code more readable. - In XSLT only, elements that have an
as
attribute to define the type of a variable, function, or parameter, also have an optional saxon:as attribute which allows additional type information to be supplied using Saxon extension syntax. If both attributes are present, then the type specified insaxon:as
must be a subtype of the type specified in theas
attribute. Typical usage might be<xsl:param name="x" as="xs:anyAtomicType" saxon:as="union(xs:date, xs:time, xs:dateTime)"/>
. This device allows union types to be used without compromising the portability of the stylesheet to an XSLT 3.0 processor that does not recognize Saxon's extension syntax (an XSLT 3.0 processor that does not recognize thesaxon:as
attribute is required to ignore it).
For example, the following code defines an XQuery function that formats a date, time, dateTime, or a string in the form of a date, time, or dateTime using the appropriate variant of the format-date/time function:
declare function local:format( $in as union(xs:dateTime, xs:date, xs:time, xs:string), $fmt as xs:string) as xs:string { typeswitch ($in) case xs:dateTime return format-dateTime($in, $fmt) case xs:date return format-date($in, $fmt) case xs:time return format-time($in, $fmt) case xs:string return local:format($in cast as union(xs:dateTime, xs:date, xs:time), $fmt) default return error() }; local:format("2016-10-07", $fmt)