How Does xsl:apply-imports Work in XSLT?
In XSLT development, the <xsl:apply-imports>
element allows an overriding template to invoke the original template
definition from an imported stylesheet. Functioning similarly to
super() or base class method calls in object-oriented
programming, it enables developers to extend existing transformation
rules without duplicating base logic. This overview breaks down how
import precedence works, how <xsl:apply-imports>
delegates processing, and how it differs from other template-matching
instructions.
Understanding Import Precedence
When modularizing XSLT code, stylesheets can bring in external
definitions using either <xsl:include> or
<xsl:import>. While included templates share the same
precedence as the including document, imported templates carry lower
import precedence.
If a template in the main (importing) stylesheet matches the same
node pattern as a template in an imported stylesheet, the main
stylesheet's template takes precedence and overrides the imported one.
Without <xsl:apply-imports>, the overridden template
remains unused unless directly targeted by a separate mode or distinct
match criteria.
The Mechanism of
<xsl:apply-imports>
When placed inside an overriding template rule,
<xsl:apply-imports> instructs the XSLT processor to
search for matching templates exclusively among stylesheets with lower
import precedence than the one containing the current rule.
Key behaviors include:
- Current Node Context:
<xsl:apply-imports>automatically applies to the current node and uses the current mode. Unlike<xsl:apply-templates>, you cannot pass aselectattribute to process child or alternate nodes. - No Infinite Recursion: Because it only considers templates with lower precedence than the active template, it does not re-invoke the overriding template.
- Parameter Propagation: In XSLT 1.0,
<xsl:apply-imports>does not support passing parameters (<xsl:with-param>). XSLT 2.0 and later versions introduced parameter passing to imported rules.
Practical Example
Consider a base stylesheet (base.xsl) that formats
standard text paragraphs:
<!-- base.xsl -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="note">
<div class="note-box">
<xsl:value-of select="." />
</div>
</xsl:template>
</xsl:stylesheet>A specialized stylesheet (custom.xsl) can import
base.xsl, override the note rule to add a
custom header icon or wrapper, and delegate the core markup generation
back to the base template:
<!-- custom.xsl -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="base.xsl"/>
<xsl:template match="note">
<aside class="callout">
<span class="badge">Notice:</span>
<xsl:apply-imports />
</aside>
</xsl:template>
</xsl:stylesheet>When transforming
<note>System maintenance at midnight.</note>,
the processor outputs:
<aside class="callout">
<span class="badge">Notice:</span>
<div class="note-box">System maintenance at midnight.</div>
</aside><xsl:apply-imports>
vs. <xsl:next-match>
In XSLT 2.0 and later, <xsl:next-match> was
introduced as a more flexible evolution of
<xsl:apply-imports>.
While <xsl:apply-imports> strictly traverses the
import precedence tree (only looking at templates in imported modules),
<xsl:next-match> evaluates both import precedence and
template priority. This means <xsl:next-match> can
fall back to lower-priority templates defined within the same stylesheet
module, whereas <xsl:apply-imports> only looks
downward into external imports.
<xsl:apply-imports> remains a foundational
construct in XSLT architecture, providing a clean mechanism for
inheritance, specialization, and maintainable stylesheet design.