Table of Contents |
Recipe 8.6. Splitting DocumentsProblemYou want to partition elements from a single document into subdocuments. SolutionXSLT 1.0For XSLT 1.0, you must rely on a widely available but nonstandard extension that allows multiple output documents.[3] 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 and some processors support exslt:document from exslt.org.[4]
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> DiscussionAlthough 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 xincludes 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> See AlsoRecipe 14.1 contains more examples that use multiple output document extensions. |
Table of Contents |