XSLT - Applying Imported Templates with <xsl:apply-imports> in XSLT
Introduction
In XSLT, large transformations are often divided into multiple stylesheets so that the code becomes easier to maintain and reuse. XSLT provides the concept of stylesheet importing, where one stylesheet can import another stylesheet using <xsl:import>.
When a stylesheet imports another stylesheet, the templates in the importing stylesheet normally have higher import precedence than templates in the imported stylesheet. This means that if both stylesheets contain templates matching the same nodes, the template in the importing stylesheet normally takes priority.
However, sometimes you do not want to completely replace the behavior of the imported template. Instead, you want to use the imported template's implementation and extend or modify its result. This is where <xsl:apply-imports> becomes useful.
What is <xsl:apply-imports>?
<xsl:apply-imports> is an XSLT instruction that tells the processor to apply a template from an imported stylesheet rather than applying the highest-precedence template again.
In simple terms, it allows a template in the main stylesheet to say:
"I have overridden the template from the imported stylesheet, but now I want to execute that original imported template as well."
The basic syntax is:
<xsl:apply-imports/>
It is normally used inside a template that is overriding a template from an imported stylesheet.
Why is <xsl:apply-imports> Needed?
Consider two stylesheets.
The first stylesheet provides a general transformation:
<xsl:template match="product">
<product>
<name>
<xsl:value-of select="name"/>
</name>
</product>
</xsl:template>
Later, another stylesheet imports this stylesheet and wants to add extra processing for product.
If the new stylesheet defines another template:
<xsl:template match="product">
<product>
<name>
<xsl:value-of select="name"/>
</name>
<category>
<xsl:value-of select="category"/>
</category>
</product>
</xsl:template>
the new template overrides the imported template.
The original template is no longer automatically executed.
If you want to retain the original processing and then add your own processing, <xsl:apply-imports> provides a mechanism for doing that.
<xsl:import> and <xsl:apply-imports> Work Together
The two instructions have different purposes.
<xsl:import> establishes the relationship between stylesheets.
<xsl:import href="base.xsl"/>
This tells the processor that the current stylesheet imports base.xsl.
<xsl:apply-imports> then allows the current stylesheet to invoke the lower-precedence template supplied by the imported stylesheet.
For example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="base.xsl"/>
<xsl:template match="product">
<xsl:apply-imports/>
<additional-information>
<xsl:value-of select="description"/>
</additional-information>
</xsl:template>
</xsl:stylesheet>
Here, the template in the current stylesheet has higher import precedence.
When product is processed, the current template is selected first. Inside that template, <xsl:apply-imports/> explicitly invokes the matching template from the imported stylesheet.
After the imported template finishes, the current template continues processing the remaining instructions.
Understanding Import Precedence
Import precedence is an important concept for understanding <xsl:apply-imports>.
Suppose there are two stylesheets:
Main stylesheet
|
| imports
v
Base stylesheet
The main stylesheet has higher import precedence than the base stylesheet.
Suppose both contain:
<xsl:template match="customer">
The processor chooses the template from the main stylesheet because it has higher import precedence.
However, from the main stylesheet's customer template, you can use:
<xsl:apply-imports/>
to invoke the matching customer template from the base stylesheet.
Conceptually, this works similarly to calling a parent implementation after overriding a method in object-oriented programming.
A Complete Example
Consider the following source XML:
<catalog>
<product>
<name>Laptop</name>
<price>75000</price>
<category>Computer</category>
</product>
</catalog>
Suppose a base stylesheet contains:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="product">
<product>
<name>
<xsl:value-of select="name"/>
</name>
<price>
<xsl:value-of select="price"/>
</price>
</product>
</xsl:template>
</xsl:stylesheet>
Save this stylesheet as:
base.xsl
Now create another stylesheet:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="base.xsl"/>
<xsl:template match="product">
<xsl:apply-imports/>
<category>
<xsl:value-of select="category"/>
</category>
</xsl:template>
</xsl:stylesheet>
The second stylesheet overrides the product template.
However, it does not completely discard the original implementation.
The instruction:
<xsl:apply-imports/>
causes the product template from base.xsl to execute.
The result will conceptually contain:
<product>
<name>Laptop</name>
<price>75000</price>
</product>
<category>Computer</category>
The important point is that the imported template performs its original processing, and then the overriding template adds additional processing.
Difference Between <xsl:apply-templates> and <xsl:apply-imports>
These two instructions may appear similar, but they serve different purposes.
<xsl:apply-templates>
<xsl:apply-templates select="product"/>
This asks the processor to find the appropriate template for the selected nodes.
The processor considers available templates and their precedence.
<xsl:apply-imports>
<xsl:apply-imports/>
This specifically asks the processor to use the applicable template from an imported stylesheet with lower import precedence.
Therefore:
| Instruction | Main purpose |
|---|---|
<xsl:apply-templates> |
Select and apply templates to nodes |
<xsl:apply-imports> |
Invoke the overridden template from an imported stylesheet |
This distinction is essential when working with modular XSLT stylesheets.
Difference Between <xsl:apply-imports> and <xsl:call-template>
Another common source of confusion is <xsl:call-template>.
Consider:
<xsl:call-template name="processProduct"/>
This invokes a named template:
<xsl:template name="processProduct">
The relationship is based on the template's name.
By contrast:
<xsl:apply-imports/>
works with template rules based on matching and import precedence.
For example:
<xsl:template match="product">
can be overridden in another imported/importing stylesheet, and <xsl:apply-imports> can invoke the lower-precedence version.
Therefore, <xsl:call-template> and <xsl:apply-imports> solve different problems.
Using <xsl:apply-imports> with Modes
Templates can also use modes.
For example:
<xsl:template match="product" mode="summary">
...
</xsl:template>
An overriding template can use:
<xsl:apply-imports/>
to invoke the lower-precedence template applicable in the same processing context.
The mode associated with the current template rule is relevant when determining which imported template should be applied.
This makes <xsl:apply-imports> useful in complex stylesheets that separate processing into different modes.
Using Parameters
Imported templates may also use parameters.
For example, a base stylesheet might contain:
<xsl:template match="product">
<xsl:param name="currency" select="'USD'"/>
<product>
<name>
<xsl:value-of select="name"/>
</name>
<currency>
<xsl:value-of select="$currency"/>
</currency>
</product>
</xsl:template>
An overriding template can invoke the imported template:
<xsl:template match="product">
<xsl:apply-imports/>
</xsl:template>
The imported template continues to operate according to its own parameter declarations and the context in which it is invoked.
When designing reusable stylesheets, parameters can therefore be combined with import precedence to create flexible transformation frameworks.
A Practical Use Case
Imagine a company maintains a standard XML-to-HTML transformation.
The organization has a base stylesheet:
company-base.xsl
It defines standard processing for:
customer
product
order
invoice
Different departments need slightly different output.
Instead of copying the entire stylesheet, a department can import the standard stylesheet:
<xsl:import href="company-base.xsl"/>
and override only the templates that need customization.
For example:
<xsl:template match="invoice">
<xsl:apply-imports/>
<department-note>
Customized department information
</department-note>
</xsl:template>
This approach preserves the standard transformation while allowing department-specific additions.
Advantages of <xsl:apply-imports>
1. Promotes stylesheet reuse
You can reuse an existing transformation rather than copying its implementation.
2. Avoids unnecessary duplication
Only the customized portion needs to be written in the new stylesheet.
3. Supports layered stylesheet design
A general stylesheet can provide default behavior while specialized stylesheets add or modify functionality.
4. Makes maintenance easier
If the base stylesheet changes, stylesheets that import it can continue using its updated behavior through <xsl:apply-imports>.
5. Supports customization
Organizations can create specialized transformations without completely rewriting a common base stylesheet.
Important Limitation
<xsl:apply-imports> is specifically associated with stylesheet importing and import precedence.
It should not be confused with stylesheet inclusion.
For example:
<xsl:include href="common.xsl"/>
and:
<xsl:import href="common.xsl"/>
are not equivalent.
An included stylesheet is effectively incorporated into the including stylesheet, while an imported stylesheet participates in an import-precedence hierarchy.
This distinction is one of the main reasons <xsl:apply-imports> exists.
When Should You Use <xsl:apply-imports>?
It is particularly useful when:
-
You have a reusable base stylesheet.
-
You need to customize only a few template rules.
-
You want to preserve the original template behavior.
-
Multiple stylesheets form a hierarchy of transformations.
-
You are building extensible XSLT applications.
-
You want specialized stylesheets to extend a general transformation.
It is less useful for simple XSLT programs where all templates are contained within one stylesheet and there is no imported template hierarchy.
Summary
<xsl:apply-imports> is an XSLT instruction used to invoke a matching template from an imported stylesheet with lower import precedence.
The typical pattern is:
<xsl:import href="base.xsl"/>
<xsl:template match="product">
<xsl:apply-imports/>
<!-- Additional or customized processing -->
</xsl:template>
The current stylesheet overrides the imported template, but <xsl:apply-imports> provides a way to reuse the original implementation.
The key idea is:
Imported stylesheet
|
| provides default template
v
Current stylesheet
|
| overrides template
v
<xsl:apply-imports/>
|
v
Original imported template
Thus, <xsl:apply-imports> is especially valuable for creating layered, reusable, and maintainable XSLT stylesheet architectures, where a specialized stylesheet needs to extend existing transformation logic rather than duplicate it.