1. xsl:copy question
2. xsl:copy or xsl:copy-of
3. Partial Copy
4. Copying only non-empty attributes


xsl:copy question

Nikolai Grigoriev

Suppose I have the following XML:

<employee FullSecurity="0">
  <name>John Doe</name>
  <department>Widget Sales</department>

I want to create a very simple XSL stylesheet which does the
following: If the FullSecurity attribute evaluates to
"true", then copy all of the source tree to the
result tree.  If the FullSecurity attribute evaluates to
"false", copy all of the source tree *except for the
<salary> element* to the result tree.

My solution is 4 lines in 2 templates (not counting the comments):

<!-- By default, copy a node with all the 
        children through. -->
<!-- Attributes are dropped; to include them, 
        use match="*|@*" -->

<xsl:template match="*">
  <xsl:copy> <xsl:apply-templates/> </xsl:copy>

<!-- Processing of salary nodes is disabled for 
   FullSecurity="0" -->
<xsl:template match="salary[/employee/@FullSecurity=0]"/>



xsl:copy or xsl:copy-of

Mike Kay +

general principle: xsl:copy-of for a deep copy, xsl:copy for a shallow copy, xsl:apply-templates for a transformation.

I.e. xsl:copy copies the current node, sub-elements are not copied xsl:copy-of copies nodes and all their descendants.


Partial Copy

Oliver Becker

> I want to write an xsl that will
> basically copy an xml tree, but allow me to chnage the values of certain
> nodes. For example:
> <highlevel>Highest Level
> <innernode>This is an innernode
> <lownode>This is a low-level node</lownode>
> </innernode>
> </highlevel>
> I want to copy this, but change the text of <innernode>, such as 
> <highlevel>Highest Level
> <innernode>I have edited this text
> <lownode>This is a low-level node</lownode>
> </innernode>
> </highlevel>

You shouldn't use xsl:copy-of. This makes a deep copy without processing the inner elements. Use xsl:copy and xsl:apply-templates - see the identity transformation in the XSLT spec http://www.w3.org/TR/xslt#copying

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

Now you can add special templates for special element nodes, such as innernode. But note: to process lownode you should call xsl:apply-templates as well. So your template becomes

<xsl:template match="innernode">
	I have edited this node
	<xsl:apply-templates select="*" />  
     <!-- only elements, no text nodes -->

I haven't tested it, but it should work.


Copying only non-empty attributes

David Carlisle

xsl:copy-of select="@*" is the standard way of copying all attributes.

However You can simplify

<xsl:template match="PERSNAME">
<xsl:element name="PERSNAME">

to either

<xsl:template match="PERSNAME">


<xsl:template match="PERSNAME">

and you can simplify

<xsl:copy-of select="@*"/>
<xsl:copy-of select="node()"/>


<xsl:copy-of select="@*|node()"/>

actually if that was exactly what you wanted, you are just copying an entire element, so you could further simplify to

<xsl:template match="PERSNAME">
<xsl:copy-of select="."/>

> Also it would be nice not to have the empty attributes 


 <xsl:template match="PERSNAME">
   <xsl:copy-of select="@*[not(.='')]|node()"/>