Patterns in XSLT 4.0
In XSLT 4.0, patterns can match any kind of item: atomic items and function items, as well as nodes. There are different kinds of pattern: predicate patterns, type patterns, and GNode patterns.
Type patterns
In XSLT 4.0, the syntax of match patterns is extended to make it easier to match maps and arrays. These extensions are available from Saxon 13 provided that XSLT 4.0 is enabled.
In particular the syntax ~item-type predicate* is allowed in a pattern,
where item-type is any item type, for instance:
- a named item type
-
(type1 | type2 | type3), a choice type -
record(...), a record type -
map(...) -
array(...)
A type pattern matches an item if the item is an instance of the
given item type, and if it satisfies each of the predicates.
Note that there is no coercion applied, so, for example, an untyped
atomic value does not match the pattern ~xs:string.
If a named item type has been declared like this:
<xsl:item-type name="cx:complex" type="record(r as xs:double, i as 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>Patterns for record types are particularly useful when JSON is processed using XSLT template rules. For example, a JSON object such as the following:
{ "firstName": "John", "lastName": "Doe", "email": "john.doe@example.com", "age": 45, "weight": 67 }can be matched with a pattern such as match="~record(firstName, lastName,
email, age, weight)". The order of properties is immaterial.
Predicates can be added as with any other pattern, for example
match="~record(firstName, lastName, department)[?department='sales']".
For information on the rules for calculating the default priority of these patterns, see the specification.
Matching Nodes
In match patterns, union node tests work like union patterns, so match="@(code,
ns:*)" is equivalent to having two separate template rules, matching the two
node tests, with different default priority.
In Saxon 13, patterns using the traditional path syntax will only match XNodes, not JNodes. (This differs from the rules in the current 4.0 specification at the time of writing.)
A path pattern in Saxon 13 will match a JNode only if an explicit JNodeType
is used. This uses the syntax "jnode" "(" Selector "," SequenceType ")".
Here Selector matches the key property of the JNode, and
may be given either as "*" (which matches any key), or as a Constant
(which may be a string literal, a numeric literal with optional minus sign, a QName literal
such as #xsi:type, or the constants true() and false()).
So for example the pattern jnode("name", xs:string) matches a JNode whose key
property is the string "name", and whose value property is an instance of
xs:string. The quotes may be omitted from the key value if it takes the form
of an NCName, so this could also be written jnode(name, xs:string).
Like other node tests, a JNode test can be qualified with an ancestor path (for example
jnode(products, array(*))//jnode(price, xs:decimal)) and/or with
predicates (for example jnode(price, xs:decimal)[empty(../discount)]).