How to Parse Non-XML Text with xsl:analyze-string
The xsl:analyze-string instruction, introduced in XSLT
2.0, provides a native mechanism to parse, match, and structure non-XML
text content using regular expressions. This article explains how
xsl:analyze-string operates, its syntax and components, and
how it transforms unstructured string data—such as CSV lines, log
entries, and delimited text—into structured XML nodes without requiring
external pre-processing tools.
The Purpose of xsl:analyze-string
Standard XSLT elements are primarily designed to navigate and transform hierarchical XML node trees. However, source documents frequently contain plain text, unstructured strings, or micro-formats within element text nodes and attributes.
The xsl:analyze-string instruction bridges this gap by
evaluating an input string against a regular expression pattern. It
iterates over the target text, automatically dividing it into parts that
match the pattern and parts that do not, allowing you to generate XML
markup or alternate text for each segment.
Syntax and Core Components
The basic structure of xsl:analyze-string relies on an
input expression, a regex pattern, and two distinct handler blocks:
<xsl:analyze-string select="$inputString" regex="pattern" flags="flags">
<xsl:matching-substring>
<!-- Executed for portions of text matching the regex -->
</xsl:matching-substring>
<xsl:non-matching-substring>
<!-- Executed for portions of text that do not match -->
</xsl:non-matching-substring>
</xsl:analyze-string>Key Attributes
select: An XPath expression evaluating to the string to be analyzed.regex: A regular expression conforming to the W3C XML Schema regex specification with XPath extensions.flags: Optional modifier flags such asi(case-insensitive),m(multiline),s(dot-all), andx(ignore whitespace).
Handling Substrings
<xsl:matching-substring>: Defines the template rules applied to every piece of text that satisfies the regular expression. Within this block, theregex-group(n)function retrieves captured parenthetical groups from the match.<xsl:non-matching-substring>: Defines the template rules applied to the remaining text surrounding the matches. This element is optional; omitting it ignores non-matching text.
Practical Applications
1. Converting Delimited Strings into Elements
When parsing comma-separated values (CSV) or lists where standard
tokenization via tokenize() is insufficient for complex
delimiters, xsl:analyze-string can identify boundaries and
capture values reliably.
2. Extracting Structured Data from Plain Text
Log messages and formatted strings often contain distinct data
points, such as dates, IP addresses, or error codes. By defining capture
groups in the regex attribute, each component can be
wrapped in a dedicated XML tag using regex-group(1),
regex-group(2), and so on.
3. Hyperlinking and Text Enrichment
In mixed-content scenarios, plain text URLs or specific keywords
within a paragraph can be targeted to generate HTML anchor tags
(<a href="...">) while keeping the surrounding
non-matching text intact.
Code Example
The following example demonstrates converting inline key-value pairs
(e.g., id:101; name:Item;) into structured XML
elements:
<xsl:variable name="rawText" select="'id:101; name:Widget; status:active;'"/>
<record>
<xsl:analyze-string select="$rawText" regex="([a-zA-Z]+):([^;]+);">
<xsl:matching-substring>
<xsl:element name="{regex-group(1)}">
<xsl:value-of select="normalize-space(regex-group(2))"/>
</xsl:element>
</xsl:matching-substring>
</xsl:analyze-string>
</record>Resulting Output
<record>
<id>101</id>
<name>Widget</name>
<status>active</status>
</record>Summary
The xsl:analyze-string instruction is an essential tool
for modern XSLT workflows. It eliminates the need for recursive template
string manipulation functions (like substring-before and
substring-after), offering a declarative, regex-driven
approach to convert unstructured text into fully structured XML
components.