Skip to content

Instantly share code, notes, and snippets.

@calaveraInfo
Last active August 11, 2023 09:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save calaveraInfo/ea33504b799511f35527054d6299dac4 to your computer and use it in GitHub Desktop.
Save calaveraInfo/ea33504b799511f35527054d6299dac4 to your computer and use it in GitHub Desktop.
Example of how to split single XML document to separate files using XSLT 2 and other advanced features

About

It is possible to create multiple output files as a result of XSL processing in XSLT 2 with tag xsl:result-document. This is usefull for example when some large database is available as a single XML document from which we need to extract only certain parts and/or modify it. This particular example takes export of accounts from the Waveset Identity Management system, filters them, modifies them and saves them in a separate file per account. This principle might be however usefull in many other cases.

This work is largely based on an example from IBM developer works

Usage

Any method for running XSL transformation may be used, but it has to support XSLT 2 spec, which is not that common. One of a few available options is to use Saxon which I like to use directly from Eclipse IDE via it's Run configurations...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://calavera.info"
exclude-result-prefixes="#all">
<xsl:output method="text"/>
<xsl:output method="xml" indent="yes" name="xml" doctype-public="waveset.dtd" doctype-system="waveset.dtd"/>
<xsl:template match="/">
<xsl:for-each select="Waveset/User">
<xsl:if test="my:filter(@name)=true()">
<xsl:variable name="filename" select="concat('out/',@name,'.xml')" />
<xsl:result-document href="{$filename}" format="xml">
<xsl:apply-templates select="."/>
</xsl:result-document>
</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- Append Services after RoleInfoList -->
<xsl:template match="RoleInfoList">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates />
</xsl:copy>
<!-- Add this service for each user -->
<Services>
<ObjectRef type='Resource' name='XYZ'/>
</Services>
</xsl:template>
<xsl:function name="my:filter">
<xsl:param name="name"/>
<xsl:choose>
<xsl:when test="$name='xyz'"><xsl:copy-of select="true()"/></xsl:when>
<xsl:otherwise><xsl:copy-of select="false()"/></xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- Standard copy template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment