Wednesday, February 21, 2007

XSL - Copy everything (recursively)

If you're just starting out with XSL transformation, you'll likely pull your hair out at some point trying to figure out how to copy a source document with exceptions and changes. Once I figured out what I was looking for, I found this solution all over the place.

This is the "identity" template.

<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()">
</xsl:apply-templates>
</xsl:copy>
</xsl:template>

This template:
- matches all attributes and all child nodes
- copies them
- recursively calles itself until it runs out of levels to process

The cool part: combine this copy template with instructions for dealing with specific elements. For example, the template below will find all "elementname" instances to copy, check for and add "attribname" (with the value specified) where it's missing. It then calls the copy everything recursively template. It could call another template like the element name template first.

<xsl:template match="elementname">
<xsl:copy>
<xsl:if test="not(@attribname)">
<xsl:attribute name="attribname">attribvalue</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*|node()">
</xsl:apply-templates>
</xsl:copy>

<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()">
</xsl:apply-templates>
</xsl:copy>
</xsl:template></xsl:template>

For knowledgeable explanations about how this works, check out these locations:

Identity Template: xsl:copy with recursion (Jesper Tverskov)

Utility Stylesheets (Bob DuCharme)

Labels: