XSLT Reference
xsl:merge
Merges multiple pre-sorted sequences into a single sorted sequence, processing each group of items with the same merge key via xsl:merge-action.
<xsl:merge><xsl:merge-source .../><xsl:merge-action>...</xsl:merge-action></xsl:merge>Description
xsl:merge performs a sorted merge of two or more input sequences, each pre-sorted by a common key. It is the XSLT 3.0 equivalent of the merge step in a merge sort algorithm. The processor reads from each source in lockstep, advancing whichever source has the smallest current key, and passes each key-group to xsl:merge-action for processing.
This is particularly powerful for combining large datasets that cannot all be loaded into memory simultaneously. Each source can be a collection of documents, a selection from an existing tree, or a streaming source. The merge happens in a single pass and does not require the processor to hold the entire merged result in memory.
Each xsl:merge must have at least one xsl:merge-source child (usually two or more) and exactly one xsl:merge-action child. The merge sources must each be sorted by the same set of xsl:merge-key expressions. Inside xsl:merge-action, the variable $current-merge-key holds the current key value, and the variable $current-merge-group holds the sequence of items from all sources that share that key.
Attributes
xsl:merge has no element-specific attributes. Its structure is defined entirely by its children: one or more xsl:merge-source elements and exactly one xsl:merge-action element.
Examples
Merging two sorted XML files by date
Source 1 (transactions-2026-q1.xml):
<transactions>
<tx date="2026-01-05" amount="100"/>
<tx date="2026-02-14" amount="250"/>
<tx date="2026-03-22" amount="75"/>
</transactions>
Source 2 (transactions-2026-q2.xml):
<transactions>
<tx date="2026-04-01" amount="180"/>
<tx date="2026-04-15" amount="320"/>
</transactions>
Stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" indent="yes"/>
<xsl:template name="xsl:initial-template">
<all-transactions>
<xsl:merge>
<xsl:merge-source name="q1" select="doc('transactions-2026-q1.xml')/transactions/tx">
<xsl:merge-key select="xs:date(@date)" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="q2" select="doc('transactions-2026-q2.xml')/transactions/tx">
<xsl:merge-key select="xs:date(@date)" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy-of select="$current-merge-group"/>
</xsl:merge-action>
</xsl:merge>
</all-transactions>
</xsl:template>
</xsl:stylesheet>
Output:
<all-transactions>
<tx date="2026-01-05" amount="100"/>
<tx date="2026-02-14" amount="250"/>
<tx date="2026-03-22" amount="75"/>
<tx date="2026-04-01" amount="180"/>
<tx date="2026-04-15" amount="320"/>
</all-transactions>
Merging with aggregation on common keys
Stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" indent="yes"/>
<xsl:template name="xsl:initial-template">
<monthly-totals>
<xsl:merge>
<xsl:merge-source name="q1" select="doc('q1.xml')//tx">
<xsl:merge-key select="month-from-date(xs:date(@date))" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="q2" select="doc('q2.xml')//tx">
<xsl:merge-key select="month-from-date(xs:date(@date))" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<month key="{$current-merge-key}"
total="{sum($current-merge-group/@amount)}"/>
</xsl:merge-action>
</xsl:merge>
</monthly-totals>
</xsl:template>
</xsl:stylesheet>
Notes
- All sources must be pre-sorted by the merge keys in the same order (ascending/descending). The processor does not sort them.
$current-merge-keyand$current-merge-groupare automatically available insidexsl:merge-action.xsl:mergeis streamable: each source can be a streaming source as long as individual sources do not need to be revisited.- When two sources have identical keys, their items are merged into the same
$current-merge-group.