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:includexsl:import
EffectTextual merge at the same precedenceLower precedence than the importing sheet
Duplicate templatesAn errorThe importing sheet wins
Order in the fileAnywhereMust come before other top-level elements
Typical useSplitting one stylesheet into filesOverriding a vendor or base library
VariablesMergedOverriding 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.

Templates and apply-templates XSLT versions, engines and where transformations run

Last refreshed 2026-09-18.