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:

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)