Saxon extensions to the W3C XSLT/XQuery specifications
Extension Functions
For the extension functions saxon:highest and saxon:lowest, the function that computes the key may now return an empty sequence, in which case the relevant item from the input is excluded from consideration (it will not feature in the result). The implementation has been made more robust in edge cases, for example where the key returns a value of an unordered type, or where the set of keys are not mutually comparable, or where they include NaN values.
A new function saxon:map-search is introduced. It is
similar to map:find
, in that it searches recursively through nested maps and arrays, but is more
versatile. It differs from map:find
in two main respects:
- Whereas
map:find
only takes as input the key value to look for,saxon:map-search
also takes a function that can be used to test the associated value. - Whereas
map:find
returns the value associated with the specified key,saxon:map-search
returns much more information about where the match was found.
The new function saxon:with-pedigree() takes a map or array as input (typically, the result of parsing JSON), and returns an equivalent map or array whose implementation has special behavior: any downward selections of nested maps/arrays using subscripting or key lookup return a map/array that has "pedigree" information; the pedigree information tells you how the map/array was selected within its containing tree, and enables you to retrace your steps. If a map or array has pedigree information, the saxon:pedigree() function returns a map, with an entry "container" identifying the containing map or array, and an entry "key" or "index" identifying the key value in the containing map, or the index value in the containing array.
The new (higher-order) extension function saxon:group-starting splits a sequence into groups, based on a starting
condition for each group. For example, the function call saxon:group-starting(following-sibling::*, fn{boolean(self::h1)})[1]?*
selects the following-sibling elements of the context item up to (and excluding) the first h1
element.
The new extension function saxon:object-map converts a Java object to an XDM map. For more information, see the "Extensibility mechanisms" changes category.
Extension Attributes
An extension attribute saxon:options has been added to xsl:evaluate: the value is an expression, which must evaluate to a map. The map allows additional Saxon-specific options for expression evaluation to be defined. Initially two options are defined:
-
allow-any-namespace
If this option is set to the value
true()
, the XPath expression may reference schema components that are present in the SaxonConfiguration
whether or not they have been imported into the stylesheet usingxsl:import-schema
. -
default-collation
The value of this option is a collation URI. This allows the default collation for evaluating the target expression to be selected dynamically (standard XSLT 3.0 facilities only allow it to be selected statically).
An accumulator rule for a
streamable accumulator that specifies phase="end"
may now also specify
saxon:capture="yes". This relaxes the rule
that the accumulator evaluation must be motionless; instead it can now be consuming. When the "end-element" event for
the accumulator rule is reached, the rule now has access to a snapshot of the entire element content (made using the
fn:snapshot
function). To avoid the snapshots become over-large, this is best used on elements that have
minimal content; in such cases it can make programming an accumulator significantly easier.
Elements that have an as
attribute to define a required type (for example, xsl:variable
,
xsl:param
, and xsl:function
) now additionally recognize a saxon:as attribute
that can be used to provide additional type information using Saxon extension syntax. For example, if the as
attribute specifies as="map(xs:string, xs:double)"
for a map used to represent a complex number, then
the additional attribute saxon:as="tuple(i: xs:double, r: xs:double)"
may be used to indicate the required
keys that must be present in the map. Similarly, if a function returns either a date or dateTime and indicates this
using as="xs:anyAtomicType"
, the return type may be more precisely described using the syntax
saxon:as="union(xs:date, xs:dateTime)"
. This allows Saxon extended types to
be used without sacrificing stylesheet portability.
Extension Instructions
A new XSLT extension instruction saxon:do is provided:
it is designed for use when invoking
XPath expressions that have side-effects. For example, <saxon:do action="$connection?close()"/>
calls the function $connection?close()
, while <saxon:do action="saxon:discard-document($doc)"/>
calls saxon:discard-document()
. Any result of the expression is discarded. The instruction is useful
in preference to xsl:sequence
firstly because the result of the expression is discarded, and secondly
because it is recognized by the optimizer as signaling an expression that is being evaluated for its side-effects.
The optimizer will attempt to avoid aggressive optimizations such as lifting the instruction
out of an xsl:for-each
loop. Note however that this does not propagate; just
because a function F
calls saxon:do
, for example, does not prevent calls on F
being moved
out of a loop.
The extension XSLT instruction saxon:tabulate-maps takes selected maps in a structure containing maps and arrays, such as might be derived by parsing JSON input, and returns these maps, expanded with information taken from containing maps and arrays.
The saxon:deep-update instruction creates a new map or array that is the same as an existing map or array except for modified content that may be several layers deep within nested maps and arrays. Typically (but not necessarily) the map or array to which it is applied will have been constructed by parsing JSON content using the parse-json() function.
As a result of the continuing popularity of the DocBook 1.0 stylesheets, which rely on the saxon:output
extension element present in Saxon 6.5.5 and earlier releases, the extension instruction
saxon6:output
(in namespace xmlns:saxon6="http://icl.com/saxon"
) has been reinstated. It is a synonym for
xsl:result-document
. This enables the DocBook 1.0 stylesheets to run without error using
Saxon-PE/EE 9.9.
XSLT Update Extension (Requires Saxon-EE). New extension instructions have been introduced to provide an XSLT equivalent of the XQuery Update capability. For example, you can delete selected attributes using the construct:
<saxon:update select="//chapter[1]"> <saxon:delete select=".//para[@deleted='yes']"/> </saxon:update>The outermost instruction is saxon:update. This has a select
attribute to
select the nodes whose subtrees will be updated. The default is select="."
. The result of the
instruction is a sequence of nodes that are modified copies of the selected nodes (unless any of these nodes
are deleted, in which case they are omitted from the result). The original tree remains unchanged.
Within the saxon:update
instruction, the following subsidiary instructions may be evaluated:
saxon:change
, saxon:delete
, saxon:insert
, saxon:rename
, saxon:replace
.
The update extension for XSLT does not provide any equivalent to XQuery updating functions; all update instructions must be contained lexically
within the saxon:update
instruction.
XPath Syntax Extensions
Saxon 9.9 implements a number of extensions to the XPath 3.1 grammar, for more information see Syntax extensions. These are enabled only if the configuration option ALLOW_SYNTAX_EXTENSIONS is set, and they require Saxon-PE or higher.
Some of these syntax extensions were issued experimentally in Saxon 9.8, and the detailed rules have been refined in the light of experience.
The tuple type syntax, for example tuple(i: xs:double, r: xs:double)
, now allows a "?" after the field name to
indicate that the field may be absent from the map, and allows a final ", *" to indicate that extra undeclared entries are permitted
in the map.
andAlso and orElse operators. These operators (often called short-circuit operators)
have the same effect as and
and or
,
but they are guaranteed to evaluate the left-hand operand before the right-hand operand, and to avoid evaluating the
right-hand operand when it is not needed. For example if ($x castable as xs:date andAlso xs:date($x) > current-date())...
ensures that no failure occurs when $x
is not a valid date. (The XPath specification offers no such guarantee
for the and
and or
operators. Saxon will occasionally rearrange the order of evaluation, as permitted
by the specification, if it thinks this will improve performance.)
XSLT syntax extensions
The syntax of match patterns is extended to make it easier to match maps and arrays (see XSLT syntax extensions: match patterns).
In particular the syntax ma-type predicate*
is allowed, where ma-type
is any of:
- ~type-alias
- tuple(...)
- map(...)
- array(...)
For example if a type alias has been declared:
<saxon:type-alias name="cx:complex" type="tuple(r: xs:double, i: xs:double)"/>Then it can be used in a match pattern to match instances of the type, with or without predicates:
<xsl:template match="~cx:complex[?i=0]">{?r}</xsl:template><xsl:template match="~cx:complex">{?r}{if (?i ge 0) then '+' else ''}{?i}i</xsl:template>The construct ~T
at the start of a pattern can be regarded as an abbreviation for
.[. instance of ~T]
.