XPath 4.0 implementation

Data model changes

Maps are now ordered: for example, if maps are produced by parsing JSON, the order of entries will be preserved when the map is serialized.

The XDM 4.0 specification changes the rules for maps so that xs:base64Binary and xs:hexBinary become mutually comparable. This has the consequence that xs:base64Binary and xs:hexBinary representations of the same value (for example xs:base64Binary("") and xs:hexBinary("")) can no longer coexist in the same map in 4.0, whereas they could coexist in 3.1. This creates a problem because Saxon 13 supports both 3.1 and 4.0 in the same product, and allows maps to be passed from 3.1 to 4.0 applications and vice versa. To solve this problem, the version number is held in the map itself, and determines how values are compared when using that map. Generally, the version number in the map is 40 if XPath 4.0 was enabled in the application that constructed the map, or 31 otherwise. However, maps constructed and returned by Saxon (for example in the result of load-xquery-module) sometimes use 40 unconditionally. The choice is only relevant when entries with binary keys xs:base64Binary or xs:hexBinary are added to the map.

An ordering is now defined over all instances of xs:duration, not just the subtypes. A duration is defined to consist of an integer number of months, and a decimal number of seconds, and the ordering relation takes the number of the months as the primary key and the number of seconds as the secondary key. This gives sensible results in cases where the number of seconds in the duration is less than the number of seconds in the shortest month; but in other cases, such as when comparing the durations P1M (one month) and P100D (one hundred days), the results are well defined and well behaved (for example, the relation is transitive and symmetric), but the answer may make little sense in terms of the real-world calendar.

Function items now have an identity property, enabling them to be compared with fn:deep-equal().

The handling of year zero in dates (specifically, types xs:dateTime, xs:date, xs:gYear, and xs:gYearMonth) has changed. Year zero is now allowed in all cases except when validating a source document against an XSD schema when XSD 1.0 processing has been requested (the default is XSD 1.1). In this situation (XSD 1.0 validation), year zero is rejected, but negative years have the XSD 1.1 (and ISO 8601) semantics: that is, year -0001 ends one year before the start of year +0001. This only affects applications doing arithmetic on dates. This change is consistent with changes in the draft 4.0 specifications, but it has been made regardless whether 4.0 processing is enabled in Saxon. The change is also conformant with XPath 3.1, which states that the results of operations on dates that cross the year 0000 are implementation-defined.

The rules for casting from xs:string when 4.0 is enabled always follow the XSD 1.1 rules. This means that when casting to xs:date or xs:dateTime, year zero is accepted regardless of whether the selected XSD version in the Configuration is 1.0 or 1.1. Similarly, the lexical form +INF (for positive infinity) is always accepted when casting to xs:double or xs:float. The XSD 1.0 rules continue to be used for casting if (a) 4.0 is not enabled, and (b) XSD 1.0 processing is selected.

XPath expressions can include namespace declarations, allowing namespace prefixes to be bound within the XPath expression, rather than relying entirely on the host language to declare namespace prefixes.

A URIQualifiedName may now supply a prefix as well as a URI and local name, in the format Q{uri}prefix:local.

In decimal format properties, it is now possible to set composite values for some properties, for example percent="%:pc" indicates that the single character "%" will be used in the picture string, but the value "pc" will appear in the output. (PR 1250)

Changes to XPath Expressions

Four new axes are implemented: following-or-self, preceding-or-self, following-sibling-or-self, and preceding-sibling-or-self. (PR 1532)

Filter expressions accept a sequence of integer positions, for example $in[3 to 5] or $in[1, 4, 7].

The pipeline operator -> is implemented, but there has been limited testing of the case where the context value is not a single item. (PR 1686)

The method call operator =?> is implemented. (PR 2143)

New operators for node comparison expressions are implemented: is-not, precedes-or-is, follows-or-is; plus precedes and follows as synonyms for << and >>.

The precedence of the otherwise operator has changed. The expression @price otherwise @cost * 2 now parses as @price otherwise (@cost * 2), not as (@price otherwise @cost) * 2. (PR 1031)

The for and let expressions now accept a larger subset of XQuery FLWOR syntax. Specifically:

Both XQuery and XPath now allow the syntax for key $k $value $v in $map to iterate over the entries in a map (in undefined order).

Changes to XPath type syntax

Named item types can now be referenced directly by name, rather than using the syntax type(alias).

Choice item types are implemented, for example the required type of a parameter in a function signature can be (map(*) | array(*)), indicating that the parameter accepts either a map or an array. The parentheses are mandatory. The local union type syntax union(xs:integer, xs:string) (which only allowed unions of atomic types) is dropped.

Arrays and maps are coerced to the required type using the 4.0 coercion rules. (PR 1501)

The implementation of enumeration types has been aligned with the current specification. Most practical use cases are unaffected, but:

XPath 4.0 features not yet implemented