Re: [xsl] copy-of too powerful or wrong

Subject: Re: [xsl] copy-of too powerful or wrong
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Mon, 9 Aug 2004 22:29:28 +0100
Hi,

> I'd like to be able to do something like this
>
> <xsl:template match="/">
> <xsl:copy-of select="@*|node()"/>
> </xsl:template>
>
> <!--SUMMARY - this comments out the Summary chunk-->
> <xsl:template
> match="/chunk/chunk[chunk-meta/title[(text()='Summary')]]"/>
[snip]

As you've found, <xsl:copy-of> does a deep copy of the selected nodes,
including attributes and children. What you're after is the identity
template:

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

This copies every node and recurses down to its children, and the
match pattern is so general that it just acts as a default template.
If you want to omit a particular subtree then you just create an empty
template, like the one above, that matches the element at the top of
the subtree.

If you want to "comment out" a particular subtree, that's a bit
harder, because the content of the comment needs to be a string, and
you want that string to be the serialised representation of the
subtree. This is one of the only situations where
disable-output-escaping is your friend (though in XSLT 2.0 you'd be
better off using character maps). You can do:

<xsl:template match="/chunk/chunk[chunk-meta/title = 'Summary']">
  <xsl:text disable-output-escaping="yes">&lt;--</xsl:text>
  <xsl:copy>
    <xsl:apply-templates select="@*|node()" />
  </xsl:copy>
  <xsl:text diable-output-escaping="no">--></xsl:text>
</xsl:template>

This will give you non-well-formed output if you already have comments
in your documents, because XML comments can't contain "--", which is
used in the delimiters for XML comments (so XML comments can't contain
other XML comments). If that's a problem, you have to do what was the
Right Thing all along and write some serialising templates along the
lines of:

<xsl:template match="*" mode="serialise">
  <xsl:text>&lt;</xsl:text>
  <xsl:value-of select="name()" />
  <xsl:for-each select="@*">
    <xsl:text> </xsl:text>
    <xsl:value-of select="name()" />
    <xsl:text>="</xsl:text>
    <xsl:value-of select="." />
    <xsl:text>"</xsl:text>
  </xsl:for-each>
  <xsl:text>></xsl:text>
  <xsl:apply-templates select="node()" mode="serialise" />
  <xsl:text>&lt;/</xsl:text>
  <xsl:value-of select="name()" />
  <xsl:text>></xsl:text>
</xsl:template>

(which get a lot more complicated if you start worrying about
indenting, empty tags, namespaces, escaping sequences of "--" and all
the other special serialisation cases) and do:

<xsl:template match="/chunk/chunk[chunk-meta/title = 'Summary']">
  <xsl:comment>
    <xsl:apply-templates select="." mode="serialise" />
  </xsl:comment>
</xsl:template>

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/

Current Thread