How Does unparsed-text() Load Non-XML into XSLT 2.0?
The unparsed-text() function in XSLT 2.0 allows
stylesheets to read external non-XML text files directly into
transformations as raw string data. Prior to XSLT 2.0, processors could
natively load only well-formed XML documents via functions like
document() or doc(). By introducing
unparsed-text(), XSLT 2.0 provides native support for
ingesting plain text formats—such as CSV, TSV, JSON, log files, or
legacy delimited data—and converting them into structured XML without
requiring external pre-processing tools or proprietary extensions.
Core Purpose and Mechanics
The primary role of unparsed-text() is to retrieve a
resource identified by a Uniform Resource Identifier (URI) and return
its contents as a single xs:string. Unlike the
doc() function, which parses the target resource with an
XML parser and produces a document node, unparsed-text()
treats the target strictly as a sequence of characters.
The function signature supports up to two arguments:
unparsed-text($href as xs:string?) as xs:string?
unparsed-text($href as xs:string?, $encoding as xs:string) as xs:string?$href: The relative or absolute URI of the file to be read. If relative, it is resolved against the static base URI of the stylesheet or element containing the expression.$encoding(optional): Specifies the character encoding (such asUTF-8,ISO-8859-1, orwindows-1252). If omitted, processors generally default to UTF-8 or attempt to detect encoding from the environment/media type.
Processing Non-XML Content in XSLT 2.0
Once non-XML content is loaded as a string via
unparsed-text(), it is typically parsed into XML elements
using XSLT 2.0's string-manipulation and regular-expression
features.
Key complementary functions and instructions include:
tokenize(): Splits raw text into lines or delimited fields using regular expressions (ideal for parsing CSV rows and columns).xsl:analyze-string: Matches complex textual patterns or grammars using regex groups, enabling structured element construction for formats like logs or configuration files.unparsed-text-available(): Tests whether a specified file exists, is accessible, and can be decoded with the specified encoding before attempting to load it, preventing fatal transformation errors.
Example: Converting CSV to XML
Below is a practical example showing how unparsed-text()
loads a comma-separated values file and transforms it into XML
nodes:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" indent="yes"/>
<xsl:template name="main">
<root>
<xsl:if test="unparsed-text-available('data.csv', 'UTF-8')">
<xsl:variable name="raw-text" select="unparsed-text('data.csv', 'UTF-8')"/>
<xsl:for-each select="tokenize($raw-text, '\r?\n')[normalize-space()]">
<row>
<xsl:for-each select="tokenize(., ',')">
<cell><xsl:value-of select="normalize-space(.)"/></cell>
</xsl:for-each>
</row>
</xsl:for-each>
</xsl:if>
</root>
</xsl:template>
</xsl:stylesheet>Benefits in Modern Pipelines
Using unparsed-text() provides several distinct
advantages in data integration pipelines:
- Pipeline Simplification: Eliminates the need for external scripts (such as Python or Bash wrappers) to convert text files into XML before running transformations.
- Hybrid Processing: Enables single-pass transformations that combine XML datasets with external lookup tables stored in flat files.
- Deterministic Encodings: Allows explicit control over character encodings, reducing character corruption across legacy text formats.