Akhoy
Akhoy

Reputation: 502

XSLT Identity Transform logic

From what I understood, the XSLT Identity transform template works by iterating through the XML structure and copying all the child nodes and attributes. But when I try to override a node to make some changes by using match with <xsl:template>, I'm not able to understand why <xsl:apply-templates/> needs to be added in the overriding template since ideally, identity transform should handle the recursion logic.

For eg:

For the XML structure:

<page site="TestSite" name="Test_QuestionAnswer1">
<testNode1>
<testNode2>
</page>

I have the following XSL transform:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="page">
<refbody>
    <xsl:attribute name="id">
        <xsl:value-of select="@name"></xsl:value-of>
    </xsl:attribute>
    <xsl:apply-templates></xsl:apply-templates> <!-- ---why is this line needed? Shouldn't the Identity transform template handle the recursion logic? -->
</refbody>
</xsl:template>
</xsl:stylesheet>

For producing the following output:

<?xml version="1.0" encoding="UTF-8"?>
<refbody id="Test_QuestionAnswer1">
<testNode1>
<testNode2>
</refbody>

Without adding the xsl:apply-templates part, it only produces the first node and doesn't loop through the children. I've been reading that Identity transform will map the whole XML document into a similar XML document as output. Why doesn't it work in this case?

Upvotes: 1

Views: 1086

Answers (2)

C. M. Sperberg-McQueen
C. M. Sperberg-McQueen

Reputation: 25034

The identity transform is implemented with a set of templates. When you add a template which matches some input with a higher priority, it is your template that determines what happens when your template is evaluated. If you want to skip some or all children, your template can do that; if you want to process an element at some distant location, your template can do that. The templates that perform the identity transform are not handling the element you matched: your template is. They cannot determine what happens in your template, including where and when apply-templates instructions should be evaluated. (If they could, how would you go about modifying the identity transformation to suppress one element with all its descendants? Or insert a table of contents at the end of the frontmatter element?)

Upvotes: 1

kjhughes
kjhughes

Reputation: 111491

The identity template you're overriding,

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

by design, explicitly uses xsl:apply-templates to continue pattern matching among the children nodes of the matched node. Any overriding template will have to follow the same form if it too wants its children to be subjected to template pattern matching.

This makes more sense than the processing model you're suggesting where children nodes would be implicitly matched because there are cases where you do not want matching to continue to be applied recursively. One simple case is where you want to delete an element (including its descendents):

<xsl:template match="ElementToDelete"/>

Having the opportunity to control whether children nodes are processed or not is an advantage because it affords control opportunities that are commonly convenient.

Upvotes: 3

Related Questions