For XSLT 1.0, you must rely on a widely available but nonstandard
extension that allows multiple output documents.[11] The
solution determines the level in the document structure to serialize
and determines the name of the resulting file. The following
stylesheet splits the salesBySalesPerson.xml
from Chapter 4 into separate files for each
salesperson. The stylesheet works in Saxon. Saxon allows use of the
XSLT 1.1 xsl:document
element when the stylesheet
version is set to 1.1.[12]
If you prefer not to use Version 1.1, then you can use
the
saxon:output
extension:
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:include href="copy.xslt"/> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="salesperson"> <xsl:variable name="outFile" select="concat('salesperson.',translate(@name,' ','_'),'.xml')"/> <!-- Non-standard saxon xsl:document! --> <xsl:document href="{$outFile}"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:copy> </xsl:document> </xsl:template> <xsl:template match="salesBySalesperson"> <xsl:apply-templates/> </xsl:template> </xsl:stylesheet>
Although the previous stylesheet is specific to Saxon, the technique
works with most XSLT 1.0 processors with only minor changes. Saxon
also has the saxon:output
extension element
(xmlns:saxon = "http://icl.com/saxon"
). Xalan uses
xalan:redirect
(xmlns:xalan = "http://xml.apache.org/xalan"
).
An interesting variation of splitting also produces an output file
that xinclude
s the generated subfiles:
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="copy.xslt"/> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="salesperson"> <xsl:variable name="outFile" select="concat('salesperson.',translate(@name,' ','_'),'.xml')"/> <xsl:document href="{$outFile}"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:copy> </xsl:document> <xi:include href="{$outFile}" xmlns:xi="http://www.w3.org/2001/XInclude"/> </xsl:template> </xsl:stylesheet>
If you worry that your XSLT processor might someday recognize
XInclude
and mistakenly try to include the same
file that was just output, you can replace the
xi:include
literal result element with
xsl:element
:
<xsl:element name="xi:include" xmlns:xi="http://www.w3.org/2001/XInclude"> <xsl:attribute name="href"> <xsl:value-of select="$outFile"/> </xsl:attribute> </xsl:element>
Recipe 12.1 contains more examples that use multiple output document extensions.