I was looking at the standard identity transform the other day and realised that for nodes other than elements, the call to apply-templates is redundant.
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
Also, although it might be intuitive to think that attributes have separate nodes for their name and value, they are in fact a single node that's copied in it's entirety by xsl:copy.
I raised this on xsl-list and suggested seperating out the attribute into a template of its own with just xsl:copy for its body:
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:copy/>
</xsl:template>
Mike Kay suggested a more logical version would be:
<xsl:template match="element()">
<xsl:copy>
<xsl:apply-templates select="@*,node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="attribute()|text()|comment()|processing-instruction()">
<xsl:copy/>
</xsl:template>
This turned out to be ideal for three reasons:
- the comma between @* and node() will mean the selected nodes will be processed in that order, removing the sorting and deduplication that takes place with union |
- apply-templates is only called when it will have an effect
- it's clearer that attributes are leaf nodes
So there it is... the identity transform for XSLT 2.0
6 comments:
Why not
<xsl:template match="/">
<xsl:copy-of select="."/>
</xsl:template>
?
That will just copy the entire input to the output - any specific templates wouldn't be called.
Yes, but isn't that what an “identity transform” is supposed to do, copy the entire input to the output?
I know what you mean. But then you're talking about the ideal overridable identity transform. Or maybe I'm just being fussy…
I ♥ XSLT. Great blog :)
I see a problem with
xsl:apply-templates select="@*, node()"/
because this changes position() in unexpected ways, because attributes are counted as well as nodes, so the first child node will have a position of 1 + number of attributes.
This is not wrong, of course, but unexpected.
Good point, but I don't think you should rely on position() in a template where you haven't also explicitly selected the nodes in that template.
If you really did want the element's position amongst its siblings in the source tree, then use xsl:number
what's missing is a match for document-node()
Post a Comment