XSLT - Generating Multiple Output Files Using <xsl:result-document> in XSLT

The <xsl:result-document> instruction is an important feature introduced in XSLT 2.0 and retained in XSLT 3.0. It allows a single XSLT transformation to generate multiple output documents, instead of being restricted to producing only one principal result. The W3C specification describes these additional outputs as secondary result documents. (W3C)

This feature is particularly useful when one XML input contains information that needs to be separated into several output files. For example, an XML document containing information about multiple departments could be transformed into separate files such as sales.xml, finance.xml, and hr.xml.

1. What is <xsl:result-document>?

Normally, an XSLT transformation produces one primary output document. For example:

<catalog>
    <product>
        <name>Laptop</name>
        <price>75000</price>
    </product>
</catalog>

An XSLT stylesheet can transform this into one HTML document:

<html>
    <body>
        <h1>Product Catalog</h1>
    </body>
</html>

However, real-world applications sometimes require multiple files from the same source.

For example, a single XML file might contain:

<employees>
    <employee department="HR">
        <name>John</name>
    </employee>
    <employee department="Finance">
        <name>David</name>
    </employee>
    <employee department="Sales">
        <name>Maria</name>
    </employee>
</employees>

Instead of producing one large output file, you may want:

HR.xml
Finance.xml
Sales.xml

This is where <xsl:result-document> becomes useful.

According to the W3C specification, <xsl:result-document> is used to construct and serialize a secondary result document. (W3C)


2. Basic Syntax

The basic syntax is:

<xsl:result-document href="filename.xml">
    <!-- Content of the output document -->
</xsl:result-document>

The href attribute specifies the location or URI of the output document.

A simple stylesheet could be:

<xsl:stylesheet version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <xsl:result-document href="output.xml">
            <employees>
                <employee>John</employee>
                <employee>David</employee>
            </employees>
        </xsl:result-document>
    </xsl:template>

</xsl:stylesheet>

When the transformation runs, an additional file named output.xml can be produced.


3. Principal Result vs Secondary Result

It is important to understand the difference between the principal result and secondary results.

The normal output of an XSLT transformation is called the principal result.

For example:

<xsl:template match="/">
    <html>
        <body>
            <h1>Employee Report</h1>
        </body>
    </html>
</xsl:template>

This creates the principal output.

When <xsl:result-document> is used, additional documents are created:

<xsl:template match="/">
    <html>
        <body>
            <h1>Employee Report</h1>
        </body>
    </html>

    <xsl:result-document href="employees.xml">
        <employees>
            ...
        </employees>
    </xsl:result-document>
</xsl:template>

Here:

Principal result
    |
    +-- Main HTML document

Secondary result
    |
    +-- employees.xml

XSLT 3.0 explicitly distinguishes the principal result from secondary results generated using <xsl:result-document>. (W3C)


4. Creating Multiple Files

The major advantage of <xsl:result-document> is that it can be executed multiple times during one transformation.

Consider this XML:

<students>
    <student>
        <name>Asha</name>
        <course>Python</course>
    </student>

    <student>
        <name>Rahul</name>
        <course>Java</course>
    </student>

    <student>
        <name>Meena</name>
        <course>Python</course>
    </student>
</students>

Suppose we want one file for each course.

The stylesheet could be:

<xsl:stylesheet version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">

        <xsl:result-document href="python.xml">
            <students>
                <xsl:for-each select="students/student[course='Python']">
                    <student>
                        <name>
                            <xsl:value-of select="name"/>
                        </name>
                        <course>
                            <xsl:value-of select="course"/>
                        </course>
                    </student>
                </xsl:for-each>
            </students>
        </xsl:result-document>

        <xsl:result-document href="java.xml">
            <students>
                <xsl:for-each select="students/student[course='Java']">
                    <student>
                        <name>
                            <xsl:value-of select="name"/>
                        </course>
                    </student>
                </xsl:for-each>
            </students>
        </xsl:result-document>

    </xsl:template>

</xsl:stylesheet>

The transformation can generate:

python.xml
java.xml

from the same input document.


5. Dynamic File Names

One of the most useful aspects of <xsl:result-document> is that the output filename can be generated dynamically.

Suppose the source document contains:

<departments>
    <department>
        <name>HR</name>
    </department>

    <department>
        <name>Finance</name>
    </department>

    <department>
        <name>Sales</name>
    </department>
</departments>

We can create one output file for every department.

<xsl:template match="/">

    <xsl:for-each select="departments/department">

        <xsl:result-document href="{lower-case(name)}.xml">

            <department>
                <name>
                    <xsl:value-of select="name"/>
                </name>
            </department>

        </xsl:result-document>

    </xsl:for-each>

</xsl:template>

The expression:

href="{lower-case(name)}.xml"

is a dynamic attribute value template.

If the department is:

<name>Finance</name>

the generated filename becomes:

finance.xml

The transformation can therefore generate:

hr.xml
finance.xml
sales.xml

This approach is especially useful when the number of output files is determined by the input data.


6. Complete Example

Consider the following input:

<company>
    <employee>
        <name>John</name>
        <department>HR</department>
    </employee>

    <employee>
        <name>David</name>
        <department>Finance</department>
    </employee>

    <employee>
        <name>Maria</name>
        <department>HR</department>
    </employee>

    <employee>
        <name>Robert</name>
        <department>Sales</department>
    </employee>
</company>

We want to create separate files for each department.

The XSLT stylesheet can be:

<xsl:stylesheet version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">

        <xsl:for-each-group
            select="company/employee"
            group-by="department">

            <xsl:variable name="department"
                          select="current-grouping-key()"/>

            <xsl:result-document
                href="{lower-case($department)}.xml">

                <employees>
                    <department>
                        <xsl:value-of select="$department"/>
                    </department>

                    <xsl:for-each select="current-group()">

                        <employee>
                            <name>
                                <xsl:value-of select="name"/>
                            </name>
                        </employee>

                    </xsl:for-each>

                </employees>

            </xsl:result-document>

        </xsl:for-each-group>

    </xsl:template>

</xsl:stylesheet>

The transformation can generate:

hr.xml
finance.xml
sales.xml

The resulting hr.xml could look like:

<employees>
    <department>HR</department>
    <employee>
        <name>John</name>
    </employee>
    <employee>
        <name>Maria</name>
    </employee>
</employees>

Similarly, finance.xml contains Finance employees, while sales.xml contains Sales employees.


7. Using Different Output Formats

<xsl:result-document> is not restricted to XML.

You can specify different serialization properties.

For XML:

<xsl:result-document
    href="employees.xml"
    method="xml"
    indent="yes">

    <employees>
        ...
    </employees>

</xsl:result-document>

For HTML:

<xsl:result-document
    href="employees.html"
    method="html">

    <html>
        <body>
            <h1>Employees</h1>
        </body>
    </html>

</xsl:result-document>

For text:

<xsl:result-document
    href="employees.txt"
    method="text">

    Employee Report
</xsl:result-document>

Therefore, a single transformation can produce different types of documents.

For example:

employees.xml
employees.html
employees.txt

The W3C specification defines serialization properties for secondary results through <xsl:result-document> and related output declarations. (W3C)


8. Specifying Encoding

You can also specify the character encoding:

<xsl:result-document
    href="employees.xml"
    method="xml"
    encoding="UTF-8">

    <employees>
        ...
    </employees>

</xsl:result-document>

UTF-8 is commonly used because it supports a wide range of characters.

For example, employee names containing characters from different languages can be preserved correctly when the output is serialized using an appropriate encoding.


9. Creating Files in Directories

The href value can also identify a location.

For example:

<xsl:result-document href="reports/hr.xml">
    ...
</xsl:result-document>

This tells the XSLT processor to create the output using the specified URI.

Dynamic directory or filename construction can also be used:

<xsl:result-document href="reports/{lower-case($department)}.xml">
    ...
</xsl:result-document>

The exact ability to write to particular locations depends on the XSLT processor and its security/configuration rules. The href is treated as a URI identifying the secondary result document rather than simply being an unrestricted operating-system filename. (W3C)


10. Using Variables for File Names

Variables can make complex output paths easier to manage.

<xsl:variable name="file-name"
              select="concat('employee-', @id, '.xml')"/>

<xsl:result-document href="{$file-name}">

    <employee>
        <xsl:value-of select="name"/>
    </employee>

</xsl:result-document>

If:

@id = "101"

the generated filename becomes:

employee-101.xml

This is useful when filenames depend on IDs, categories, dates, or other source values.


11. Avoiding Duplicate Output URIs

A very important rule is that different xsl:result-document instructions should not unintentionally write to the same output URI during one transformation.

For example:

<xsl:for-each select="company/employee">

    <xsl:result-document href="employee.xml">
        ...
    </xsl:result-document>

</xsl:for-each>

If there are 100 employees, the stylesheet attempts to generate the same:

employee.xml

100 times.

This is problematic because the processor cannot safely treat all of these as independent secondary result documents.

A better approach is to generate unique filenames:

<xsl:result-document href="employee-{@id}.xml">
    ...
</xsl:result-document>

For employees with IDs 101, 102, and 103, the files become:

employee-101.xml
employee-102.xml
employee-103.xml

When designing a multiple-output transformation, unique output URIs should therefore be planned carefully.


12. Relationship with <xsl:output>

<xsl:output> defines serialization characteristics for the principal output and can also provide output characteristics that are relevant to result documents.

For example:

<xsl:output
    method="xml"
    encoding="UTF-8"
    indent="yes"/>

A result document can also specify serialization attributes directly:

<xsl:result-document
    href="data.xml"
    method="xml"
    indent="yes">
    ...
</xsl:result-document>

This allows the stylesheet to control how a particular secondary result is serialized.

The W3C specification explains that serialization is distinct from the transformation itself: the transformation constructs the result, and serialization determines how that result is written in a particular representation such as XML, HTML, or text. (W3C)


13. Practical Applications

<xsl:result-document> is useful in many practical situations.

Generating departmental reports

One XML file containing all departments can produce:

hr-report.xml
finance-report.xml
sales-report.xml

Generating individual customer documents

A customer database represented as XML can be transformed into:

customer-1001.xml
customer-1002.xml
customer-1003.xml

Creating website pages

An XML content repository can be transformed into multiple HTML pages:

index.html
products.html
services.html
contact.html

Generating invoices

An XML document containing many invoices can be divided into individual files:

invoice-001.xml
invoice-002.xml
invoice-003.xml

Generating reports in different formats

One transformation can generate several secondary documents, such as:

report.xml
report.html
report.txt

This makes XSLT particularly useful for document-generation systems.


14. Advantages of <xsl:result-document>

The major advantages include:

  1. Multiple outputs from one transformation
    A single source document can produce many output documents.

  2. Dynamic file generation
    Output filenames can be generated from source data.

  3. Reduced preprocessing
    There is often no need to split the source XML manually before transformation.

  4. Flexible output formats
    XML, HTML, and text outputs can be generated.

  5. Useful for large document-generation workflows
    One transformation can produce a collection of related documents.

  6. Better organization of generated content
    Large output data can be divided into smaller, logically organized files.


15. Important Limitations and Considerations

Although <xsl:result-document> is powerful, developers should consider several factors.

First, it is a feature of XSLT 2.0 and later, so an XSLT 1.0 processor cannot use it. XSLT 3.0 continues to support secondary result documents. (W3C)

Second, the XSLT processor must have permission to create the requested output resources. A stylesheet cannot necessarily write arbitrary files on a system.

Third, output URIs should be designed carefully to prevent multiple result documents from targeting the same location.

Fourth, generating thousands or millions of separate files can create operational and storage overhead. Multiple output documents are most useful when separating data into meaningful document units.

Finally, secondary result serialization can produce errors. The XSLT 3.0 specification treats a serialization error occurring while producing a secondary result as a dynamic error associated with the <xsl:result-document> instruction. (W3C)


16. <xsl:result-document> vs Normal Output

Feature Normal XSLT Output <xsl:result-document>
Main purpose Produces the principal result Produces secondary results
Number of documents Normally one Multiple
Filename Usually controlled externally Can be specified using href
Dynamic filename Limited Supported
XML output Yes Yes
HTML output Yes Yes
Text output Yes Yes
Useful for document splitting Limited Very useful
Available in XSLT 1.0 No No
Available in XSLT 2.0 Yes Yes
Available in XSLT 3.0 Yes Yes

17. Key Syntax to Remember

The basic pattern is:

<xsl:result-document href="output.xml">
    <!-- Output content -->
</xsl:result-document>

With a dynamic filename:

<xsl:result-document href="{@id}.xml">
    <!-- Output content -->
</xsl:result-document>

With serialization options:

<xsl:result-document
    href="output.xml"
    method="xml"
    encoding="UTF-8"
    indent="yes">

    <!-- Output content -->

</xsl:result-document>

Conclusion

<xsl:result-document> provides a structured way to generate multiple secondary output documents from a single XSLT transformation. Instead of forcing all transformed information into one large output, it allows the stylesheet to divide the results into logically separate XML, HTML, or text files.

Its strongest use cases include generating departmental reports, individual customer documents, invoices, web pages, and other collections of related documents. Dynamic filenames make the feature especially powerful because output files can be created according to values found in the source XML.

For modern XSLT development, <xsl:result-document> is an important feature to understand because it moves XSLT beyond simple one-input/one-output transformations and makes it suitable for more sophisticated document-generation workflows. The W3C XSLT 3.0 Recommendation formally defines this mechanism for producing secondary result documents. (W3C)