Querying, Transformation & Real-World XML
XSLT: Transforming XML
XSLT transforms XML documents into other formats — HTML pages, different XML structures, plain text, or CSV. It is a functional, template-based language that applies rules to an XML input and produces an output document.
What XSLT Does
XSLT (eXtensible Stylesheet Language Transformations) takes an XML input document and a stylesheet (itself an XML document with transformation rules), and produces an output. The input is always XML; the output can be XML, HTML, or plain text.
The core use cases:
- Transform data XML into HTML reports for display
- Convert one XML schema to another for system integration
- Generate documentation from XML source
- Transform RSS feeds into styled web pages
- Produce multiple output formats from a single XML source
The XSLT Processing Model
- The XSLT processor reads the input XML and builds a tree
- It reads the stylesheet and compiles the template rules
- Starting from the document root, it matches nodes against templates
- When a template matches, the processor executes it — outputting literal markup and using XSLT instructions to navigate and extract data
- The result tree is serialized to the output format
This model is pull-based and declarative: you define what to do when you encounter each type of node, and the processor handles traversal.
A Complete XSLT Stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Book Catalog</title>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ccc; padding: 8px; }
.expensive { background: #fff3cd; }
</style>
</head>
<body>
<h1>Book Catalog</h1>
<table>
<tr><th>Title</th><th>Author</th><th>Price</th></tr>
<xsl:apply-templates select="catalog/book">
<xsl:sort select="price" data-type="number" order="ascending"/>
</xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="book">
<tr>
<xsl:if test="price > 15">
<xsl:attribute name="class">expensive</xsl:attribute>
</xsl:if>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="author"/></td>
<td>$<xsl:value-of select="price"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>Core XSLT Elements
Output and Templates
`<xsl:output method="">` — declares the output format: method="html", method="xml", or method="text". Add indent="yes" for pretty-printed output.
`<xsl:template match="XPath">` — a rule that fires when the processor encounters a matching node. The match attribute accepts XPath patterns: match="/" (document root), match="book" (any book element), match="book[@genre='fiction']" (fiction books only).
`<xsl:apply-templates select="XPath"/>` — hands off processing to matching templates. The recursive heart of XSLT — each template processes its nodes and calls apply-templates for children.
Data Extraction
`<xsl:value-of select="XPath"/>` — outputs the string value of the selected node. The primary data extraction instruction. Escapes special characters automatically.
`<xsl:copy-of select="XPath"/>` — deep-copies a node including all children and attributes. Use when you want to reproduce part of the input unchanged.
Iteration and Conditionals
`<xsl:for-each select="XPath">` — iterates over every node in the selection. Within the loop, the context node shifts to each selected node in turn.
<xsl:for-each select="catalog/book">
<xsl:sort select="author" order="ascending"/>
<li><xsl:value-of select="title"/> by <xsl:value-of select="author"/></li>
</xsl:for-each>`<xsl:if test="condition">` — conditional output. No else clause.
`<xsl:choose>/<xsl:when>/<xsl:otherwise>` — multi-branch conditional (if/else if/else):
<xsl:choose>
<xsl:when test="price > 20">premium</xsl:when>
<xsl:when test="price > 10">standard</xsl:when>
<xsl:otherwise>budget</xsl:otherwise>
</xsl:choose>Dynamic Output
`<xsl:attribute name="">` — generates an attribute on the current output element:
<a>
<xsl:attribute name="href">
<xsl:value-of select="concat('/books/', @id)"/>
</xsl:attribute>
<xsl:value-of select="title"/>
</a>`<xsl:variable name="" select="">` — declares a read-only variable (XSLT 1.0 variables cannot be reassigned):
<xsl:variable name="book-count" select="count(//book)"/>
<p>Total: <xsl:value-of select="$book-count"/> books</p>Template Matching vs. for-each
This is the fundamental XSLT design choice.
`<xsl:for-each>` is imperative — "loop through these nodes and do this." Familiar to programmers, reads like a for-loop, but does not scale well to complex transformations.
Template matching (<xsl:apply-templates>) is declarative — define what to do with each node type, and let the processor traverse. More modular, more maintainable for complex transformations. Each template has one responsibility.
Best practice: use templates for the overall document structure, use for-each for simple lists within a template.
The Identity Transform
The identity transform copies input to output unchanged — useful as a base you modify:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>Apply this first, then add specific templates that override it for elements you want to change. This is the XSLT equivalent of method overriding.
Running XSLT
Browser: link stylesheet to XML with a processing instruction:
<?xml-stylesheet type="text/xsl" href="catalog.xsl"?>Command line (Linux/Mac):
xsltproc catalog.xsl data.xml > output.htmlPython:
from lxml import etree
transform = etree.XSLT(etree.parse("catalog.xsl"))
result = transform(etree.parse("data.xml"))
with open("output.html", "wb") as f:
f.write(bytes(result))Java — built into the JDK via javax.xml.transform.TransformerFactory.
JavaScript (browser):
const xslt = new XSLTProcessor();
xslt.importStylesheet(stylesheetDocument);
const result = xslt.transformToDocument(inputDocument);XSLT in Modern Workflows
XSLT may seem dated, but it appears in more modern contexts than you might expect:
- Report generation: transform XML data exports from databases, ERP systems, or IoT platforms into styled HTML reports
- Data migration: convert XML from one schema format to another when integrating systems (common in healthcare HL7 and financial FIX protocol migrations)
- Build pipelines: Maven POM processing, DocBook → HTML publishing pipelines
- XSLT 3.0 (Saxon): adds streaming for large documents, JSON input/output, higher-order functions, and maps — making it relevant for modern data engineering
The declarative template model in XSLT is conceptually identical to the transformation pipelines in Power Query, n8n, and data engineering tools — input, rules, output. Understanding XSLT's model builds good instincts for data transformation at every level.
See [XML in the Wild](/tutorials/xml-fundamentals/xml-in-the-wild) for where XSLT is used in real production systems, and the [XML, XPath & XSLT Reference](/tutorials/xml-fundamentals/reference/xml-reference) for the complete element and function reference.
Example
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<!-- Root template -->
<xsl:template match="/">
<ul>
<xsl:apply-templates select="catalog/book">
<xsl:sort select="price" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:template>
<!-- Book template -->
<xsl:template match="book">
<li>
<xsl:value-of select="title"/>
<xsl:text> — $</xsl:text>
<xsl:value-of select="price"/>
<xsl:if test="@genre='fiction'">
<xsl:text> (fiction)</xsl:text>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>