Reusing stylesheets: includes, imports and named templates
Sharing templates across stylesheets relies on precedence rules that decide which duplicate wins, so know the difference between include and import.
include versus import
xsl:include | xsl:import | |
|---|---|---|
| Effect | Textual merge at the same precedence | Lower precedence than the importing sheet |
| Duplicate templates | An error | The importing sheet wins |
| Order in the file | Anywhere | Must come before other top-level elements |
| Typical use | Splitting one stylesheet into files | Overriding a vendor or base library |
| Variables | Merged | Overriding sheet takes precedence |
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="base.xsl"/>
<xsl:include href="utilities.xsl"/>
<!-- Beats the same match rule in base.xsl without any priority attribute -->
<xsl:template match="item">
<div class="item"><xsl:apply-templates select="*"/></div>
</xsl:template>
</xsl:stylesheet>- Imported templates can still be invoked explicitly with
call-template, so a base library can expose both hooks and overridable rules. - Include paths are resolved relative to the including stylesheet, which makes a library portable if you keep it self-contained.
- Both are resolved at compile time, so a missing file fails the transform rather than falling back.
Named templates, modes and attribute sets
<xsl:template name="price-row">
<xsl:param name="item"/>
<xsl:param name="currency" select="'GBP'"/>
<tr>
<td><xsl:value-of select="$item/title"/></td>
<td><xsl:value-of select="format-number($item/price, '0.00')"/> <xsl:value-of select="$currency"/></td>
</tr>
</xsl:template>
<xsl:template match="/">
<table>
<xsl:for-each select="//item">
<xsl:call-template name="price-row">
<xsl:with-param name="item" select="."/>
<xsl:with-param name="currency" select="'EUR'"/>
</xsl:call-template>
</xsl:for-each>
</table>
</xsl:template><!-- Modes let one element render two different ways -->
<xsl:template match="item" mode="nav"><a href="{@url}"><xsl:value-of select="title"/></a></xsl:template>
<xsl:template match="item" mode="body"><h2><xsl:value-of select="title"/></h2></xsl:template>
<!-- Attribute sets collect repeated attribute groups -->
<xsl:attribute-set name="table">
<xsl:attribute name="border">0</xsl:attribute>
<xsl:attribute name="cellpadding">4</xsl:attribute>
</xsl:attribute-set>
<xsl:template match="table"><table xsl:use-attribute-sets="table">...</table></xsl:template>💡
A named template carries no node matching, so it is the right place for reusable logic that is not about a node type — formatting a price, building a URL, emitting a table cell. Match templates describe the data; named templates describe operations.
FAQ
Why is the imported template winning?
Because higher import precedence beats lower, and the importing stylesheet always has the highest precedence. If two imported sheets conflict, the one imported last has lower precedence.
Can I apply templates in a mode that has no matching template?
Yes. The built-in rules apply, so text and further templates are processed normally unless you supply an explicit mode with no rules, in which case child elements fall through silently.
Related
Templates and apply-templates XSLT versions, engines and where transformations run
Last refreshed 2026-09-18.