How to Use matches, replace, and tokenize in XSLT 2.0?
XSLT 2.0 introduces native support for regular expressions through
standard XPath 2.0 functions, eliminating the need for complex recursive
templates or proprietary extension functions when parsing text. This
guide covers how matches(), replace(), and
tokenize() operate, their underlying XML Schema-based regex
engine, and practical examples demonstrating text validation, pattern
substitution, and string splitting.
The Regular Expression Engine in XSLT 2.0
XSLT 2.0 regular expressions follow the W3C XML Schema regular
expression dialect extended with Perl-like features. All three primary
functions support an optional flags parameter:
i: Case-insensitive matching.m: Multi-line mode, where^and$match the start and end of individual lines rather than the entire string.s: Dot-all mode, allowing.to match newline characters.x: Ignores whitespace within the pattern to allow comments and formatted expressions.
1. Pattern Testing with
matches()
The matches() function evaluates whether an input string
contains a match for a specified pattern, returning a boolean
true() or false().
Syntax
matches($input as xs:string?, $pattern as xs:string) as xs:boolean
matches($input as xs:string?, $pattern as xs:string, $flags as xs:string) as xs:boolean
Usage and Behavior
Unlike the XML Schema pattern facet, which enforces a
full-string match by default, matches() checks for a
substring match unless explicitly anchored with ^ and
$.
<xsl:if test="matches(@code, '^[A-Z]{3}-\d{4}$')">
<xsl:text>Valid Product Code</xsl:text>
</xsl:if>Case-insensitive matching can be achieved with the "i"
flag:
<xsl:value-of select="matches(title, 'xslt', 'i')"/>2. String Substitution with
replace()
The replace() function searches an input string for a
pattern and substitutes all occurrences with a replacement string.
Syntax
replace($input as xs:string?, $pattern as xs:string, $replacement as xs:string) as xs:string
replace($input as xs:string?, $pattern as xs:string, $replacement as xs:string, $flags as xs:string) as xs:string
Capturing Groups and Backreferences
The replacement string can reference captured groups from the pattern
using $1, $2, through $n. A
literal dollar sign must be escaped as \$, and a literal
backslash must be escaped as \\.
<!-- Converts 'YYYY-MM-DD' to 'DD/MM/YYYY' -->
<xsl:value-of select="replace(date, '^(\d{4})-(\d{2})-(\d{2})$', '$3/$2/$1')"/>If the pattern matches multiple occurrences across the string,
replace() replaces every non-overlapping instance:
<!-- Normalizes all consecutive whitespace characters into a single space -->
<xsl:value-of select="replace(description, '\s+', ' ')"/>3. String Splitting with
tokenize()
The tokenize() function splits an input string into a
sequence of strings (xs:string*) using a regex pattern as
the delimiter.
Syntax
tokenize($input as xs:string?, $pattern as xs:string) as xs:string*
tokenize($input as xs:string?, $pattern as xs:string, $flags as xs:string) as xs:string*
Processing Sequences
Because tokenize() returns an XPath sequence, the result
can be iterated using xsl:for-each or queried using
sequence functions.
<xsl:variable name="keywords" select="tokenize('apple, banana; orange,grape', '[,;]\s*')"/>
<keywords>
<xsl:for-each select="$keywords">
<keyword><xsl:value-of select="."/></keyword>
</xsl:for-each>
</keywords>Handling Edge Cases
If the delimiter pattern matches at the start or end of the string,
or matches consecutive occurrences, tokenize() produces
empty strings ("") in the sequence. If the input string is
an empty sequence or zero-length string, tokenize() returns
an empty sequence.
Function Comparison
| Function | Return Type | Primary Purpose | Common Use Case |
|---|---|---|---|
matches() |
xs:boolean |
Evaluates if pattern exists | Schema validation, conditional logic |
replace() |
xs:string |
Substitutes matched text | Reformatting dates, stripping tags, cleanup |
tokenize() |
xs:string* |
Splits string by delimiter regex | Parsing CSV/TSV data, token processing |
XSLT 2.0 also includes the <xsl:analyze-string>
instruction for scenarios requiring conditional processing of matched
and non-matched substrings, complementing the basic functional
capabilities provided by matches(), replace(),
and tokenize().