XSLT

XSLT, the Extensible Stylesheet Language for Transformations, is a declarative language designed to transform XML documents into other formats. It is commonly used to produce HTML pages, normalized XML, plain text, reports, and data-exchange payloads. XSLT works with XPath to locate nodes in a source tree and template rules to determine what should be generated.

Unlike a procedural converter, an XSLT stylesheet does not normally describe every instruction in execution order. Instead, it defines rules such as “when this element is encountered, create this output.” This model makes transformation logic easier to maintain, reuse, and test.
A stylesheet is itself an XML document. Its root element is normally <xsl:stylesheet> or <xsl:transform>, and it must declare the official XSLT namespace:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html" encoding="UTF-8"/>

  <xsl:template match="/">
    <!-- Transformation rules go here -->
  </xsl:template>

</xsl:stylesheet>

The version attribute identifies the language version, while the xmlns:xsl declaration makes the XSLT instructions available to the processor. The <xsl:output> element controls the result format and encoding.

Template rules are the central building block of a stylesheet. A rule uses match to identify source nodes and apply-templates to pass processing to more specific rules:

<xsl:template match="/">
  <xsl:apply-templates select="books/book"/>
</xsl:template>

<xsl:template match="book">
  <p><xsl:value-of select="title"/></p>
</xsl:template>

In this example, the root template selects each book element. The processor then applies the template whose pattern matches a book element. If no matching rule exists, built-in template rules may provide basic behavior, such as processing the text content of a node.

Selecting Data with XPath

XPath expressions identify nodes, attributes, and values within an XML document. They can be absolute or relative to the current context node:

  • /books/book selects every book element under the document root.
  • title selects the title child of the current node.
  • @id selects the current node’s id attribute.
  • book[price > 50] selects books whose numeric price exceeds 50.
  • book[1] selects the first book in the current context.

The <xsl:value-of> instruction inserts the value of a selected node or expression into the result. When more precise control is needed, other output instructions can create elements and attributes explicitly.

Consider the following source document:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book id="b1">
    <title>Learning XML</title>
    <price>39.80</price>
  </book>
  <book id="b2">
    <title>Practical XSLT</title>
    <price>59.00</price>
  </book>
</books>

A stylesheet can transform it into an HTML table:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html" encoding="UTF-8" indent="yes"/>

  <xsl:template match="/">
    <html>
      <body>
        <h2>Book Catalog</h2>
        <table border="1">
          <tr>
            <th scope="col">ID</th>
            <th scope="col">Title</th>
            <th scope="col">Price</th>
          </tr>

          <xsl:for-each select="books/book">
            <xsl:sort select="price" data-type="number"/>

            <tr>
              <td><xsl:value-of select="@id"/></td>
              <td><xsl:value-of select="title"/></td>
              <td><xsl:value-of select="price"/></td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

The <xsl:for-each> instruction processes a selected node set, while <xsl:sort> orders that set before the row content is generated. Specifying data-type="number" ensures that prices are compared numerically rather than alphabetically.

Conditional and Iterative Processing

XSLT provides several instructions for controlling the shape of a transformation:

  • <xsl:if test="..."> includes content when a condition is true.
  • <xsl:choose> selects one branch from several alternatives.
  • <xsl:for-each select="..."> iterates over a node set or sequence.
  • <xsl:sort> controls the order of processed items.
  • <xsl:copy> and <xsl:copy-of> duplicate source nodes.

A typical multi-branch condition might look like this:

<xsl:choose>
  <xsl:when test="price >= 50">
    <span class="premium">Premium title</span>
  </xsl:when>
  <xsl:when test="price >= 25">
    <span class="standard">Standard title</span>
  </xsl:when>
  <xsl:otherwise>
    <span class="budget">Budget title</span>
  </xsl:otherwise>
</xsl:choose>

Although <xsl:for-each> is convenient for small transformations, <xsl:apply-templates> is often the better choice for larger stylesheets. Template rules can be overridden, reused, tested independently, and organized around the structure of the source document.

For example, a list view can delegate each book to a dedicated template:

<xsl:template match="/">
  <section>
    <h1>Available Books</h1>
    <ul>
      <xsl:apply-templates select="books/book"/>
    </ul>
  </section>
</xsl:template>

<xsl:template match="book">
  <li>
    <xsl:value-of select="title"/>
    — <xsl:value-of select="price"/>
  </li>
</xsl:template>

Reusable Templates and Modes

Named templates are useful when the same formatting task appears in several places:

<xsl:template name="currency">
  <xsl:param name="amount" select="0"/>
  <xsl:text>$</xsl:text>
  <xsl:value-of select="$amount"/>
</xsl:template>

A caller can supply a value with <xsl:with-param>:

<xsl:call-template name="currency">
  <xsl:with-param name="amount" select="price"/>
</xsl:call-template>

Modes allow the same source node to be rendered differently in different contexts. A summary rule and a detailed rule can both match book without conflicting:

<xsl:template match="book" mode="summary">
  <span><xsl:value-of select="title"/></span>
</xsl:template>

<xsl:template match="book" mode="detail">
  <article>
    <h2><xsl:value-of select="title"/></h2>
    <p><xsl:value-of select="description"/></p>
  </article>
</xsl:template>

The caller chooses the appropriate mode:

<xsl:apply-templates select="books/book" mode="summary"/>

This technique is valuable for creating multiple presentations from the same data, such as compact indexes, detailed catalogs, and machine-readable summaries.

XSLT 1.0, 2.0, and 3.0

The three major versions differ significantly in expressive power:

  • XSLT 1.0 is the most widely supported version and works with XPath 1.0. It is suitable for many straightforward XML-to-HTML and XML-to-XML transformations.
  • XSLT 2.0 adds sequences, XPath 2.0, user-defined functions, grouping, and richer data handling.
  • XSLT 3.0 builds on XSLT 2.0 and introduces XPath 3.1, maps, arrays, additional streaming capabilities, and package-oriented features.

New projects often use XSLT 3.0 when the available processor supports it. Saxon is a common implementation for versions 2.0 and 3.0. The trade-off is that XSLT 1.0 has broader native browser and library support.

Version selection should be driven by both required features and deployment constraints. A legacy browser integration may favor XSLT 1.0, while a server-side pipeline can benefit from the sequence and function model of XSLT 3.0.

Running and Deploying Stylesheets

Saxon can execute a transformation from the command line:

java -jar saxon.jar -s:books.xml -xsl:books.xsl -o:books.html

A browser can also load an XML document with an associated stylesheet:

<?xml-stylesheet type="text/xsl" href="books.xsl"?>
<books>
  <!-- Source data -->
</books>

Browser support is generally limited to XSLT 1.0, however. Server-side processing offers broader version support and is usually more appropriate for production workflows. Common integration options include Java’s TransformerFactory, .NET’s XslCompiledTransform, and Python’s lxml library.

Because XML processors may resolve external entities or external resources, transformations should not automatically trust uploaded XML or stylesheets. External entity resolution should be disabled where possible, document access should be restricted, and resolvers should use an explicit allowlist. Similarly, <xsl:output> with disable-output-escaping requires careful review because it can create injection risks in downstream systems.

When XSLT Is the Right Tool

XSLT is well suited to deterministic, rule-driven transformations involving structured XML. Typical uses include:

  • Rendering XML content as HTML or accessible web components.
  • Converting legacy XML formats into newer schemas.
  • Generating reports, feeds, and plain-text exports.
  • Normalizing data for system integration.
  • Producing multiple views from a common source document.

It is less suitable when a task depends on complex state management, extensive business calculations, or interactions with arbitrary external services. In those cases, a conventional programming language and a dedicated XML library may offer clearer control.

For maintainability, stylesheets should use meaningful template names, separate matching logic from formatting details, define external parameters explicitly, and include representative test cases. XSLT remains a powerful option whenever the central problem is “given this XML structure, produce that output structure” in a predictable and repeatable way.