Sponsored

Posts

XSLT string functions: complete reference with examples

28 Mar 2025

Complete guide to XSLT and XPath string functions: substring, contains, replace, tokenize, normalize-space and more. With practical examples.

String manipulation is one of the most common tasks in XSLT. Whether you are formatting output, parsing codes, or normalising values from external systems, XPath provides a rich set of string functions. This reference covers the most useful ones with examples you can run in XSLT Playground.

Basic string functions (XSLT 1.0+)

string-length

Returns the number of characters in a string.

<xsl:value-of select="string-length('hello')"/>  <!-- 5 -->
<xsl:value-of select="string-length(title)"/>     <!-- length of title element text -->

substring

Extracts a portion of a string. Arguments: string, start position (1-based), optional length.

<xsl:value-of select="substring('ABCDEF', 2, 3)"/>   <!-- BCD -->
<xsl:value-of select="substring('ABCDEF', 4)"/>       <!-- DEF -->

substring-before and substring-after

Split a string on a delimiter.

<xsl:value-of select="substring-before('2024-11-28', '-')"/>  <!-- 2024 -->
<xsl:value-of select="substring-after('user@example.com', '@')"/>  <!-- example.com -->

contains, starts-with, ends-with

Test membership without extracting.

<xsl:if test="contains(email, '@')">...</xsl:if>
<xsl:if test="starts-with(code, 'EUR')">...</xsl:if>
<!-- ends-with requires XSLT 2.0+ -->
<xsl:if test="ends-with(filename, '.xml')">...</xsl:if>

concat

Joins strings together. Takes any number of arguments.

<xsl:value-of select="concat(firstname, ' ', lastname)"/>
<xsl:value-of select="concat('ID-', format-number(id, '0000'))"/>

normalize-space

Strips leading and trailing whitespace, and collapses internal whitespace to single spaces. Essential for cleaning values from XML sources.

<xsl:value-of select="normalize-space(description)"/>

translate

Replaces characters one-for-one. Useful for simple case conversion or character removal.

<!-- uppercase (XSLT 1.0 approach) -->
<xsl:value-of select="translate(name, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>

<!-- remove digits -->
<xsl:value-of select="translate(code, '0123456789', '')"/>

Advanced string functions (XSLT 2.0+)

upper-case and lower-case

No longer need translate for case conversion.

<xsl:value-of select="upper-case(name)"/>
<xsl:value-of select="lower-case(status)"/>

replace

Regex-based substitution. Much more powerful than translate.

<!-- remove all non-digits -->
<xsl:value-of select="replace(phone, '[^0-9]', '')"/>

<!-- normalise whitespace to single space -->
<xsl:value-of select="replace(description, '\s+', ' ')"/>

<!-- mask last 4 digits of card number -->
<xsl:value-of select="replace(card, '\d(?=\d{4})', '*')"/>

matches

Tests a string against a regex.

<xsl:if test="matches(email, '^[^@]+@[^@]+\.[^@]+$')">
  <!-- valid-looking email -->
</xsl:if>

tokenize

Splits a string into a sequence using a regex delimiter. Returns a sequence of strings.

<!-- split CSV line -->
<xsl:for-each select="tokenize(csv-line, ',')">
  <item><xsl:value-of select="normalize-space(.)"/></item>
</xsl:for-each>

<!-- split on any whitespace -->
<xsl:variable name="words" select="tokenize(sentence, '\s+')"/>
<xsl:value-of select="count($words)"/> <!-- word count -->

string-join

The inverse of tokenize. Joins a sequence with a separator.

<xsl:value-of select="string-join(//tag/text(), ', ')"/>
<!-- "xml, xslt, saxon" -->

format-number

Formats a number as a string with a picture pattern.

<xsl:value-of select="format-number(1234567.89, '#,##0.00')"/>
<!-- 1,234,567.89 -->
<xsl:value-of select="format-number(0.175, '0.00%')"/>
<!-- 17.50% -->

format-date and format-dateTime

Format xs:date and xs:dateTime values using picture strings.

<xsl:value-of select="format-date(xs:date('2024-11-28'), '[D01]/[M01]/[Y]')"/>
<!-- 28/11/2024 -->

<xsl:value-of select="format-dateTime(current-dateTime(), '[H01]:[m01]:[s01]')"/>
<!-- 14:35:22 -->

Practical patterns

Extract domain from URL:

<xsl:variable name="after-proto" select="substring-after(url, '//')"/>
<xsl:value-of select="substring-before($after-proto, '/')"/>

Pad a number with leading zeros:

<xsl:value-of select="format-number(id, '000000')"/>

Check if a node text is numeric:

<xsl:if test="matches(normalize-space(amount), '^\d+(\.\d+)?$')">

All of these work in XSLT Playground. Set the version to 2.0 or 3.0 for the functions that require it.