Reputation: 1065
I'd like to know if there's any difference between:
<xsl:template match="/*">
<xsl:element name="{name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
and:
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
Upvotes: 1
Views: 553
Reputation: 22617
The xsl:element
element generates a new element node.
xsl:copy
copies a context item to the output sequence. However, the said context item does not have to be an element node. In your case:
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
The context item is indeed an element. This has the following consequences:
xsl:copy
also copies the element's namespaces if anyxsl:copy
is used if the context item is an element. In your example, the sequence constructor is <xsl:apply-templates/>
Summary: xsl:copy
can copy any kind of node (atomic value, document, element, text, attribute, processing instruction, comment, namespace) whereas xsl:element
is solely capable of generating element nodes.
Usage: Use xsl:copy
to effectively copy nodes from input XML to the output sequence. Use xsl:element
only if element names are dynamic, that is, not known beforehand.
As an aside note, with XSLT 2.0 you can control the treatment of namespaces explicitly with the attributes copy-namespaces
and inherit-namespaces
.
Upvotes: 1
Reputation: 116959
There is at least one difference. Given the following input:
<root xmlns="htpp://www.example.com/my">my text</root>
this template:
<xsl:template match="/*">
<xsl:element name="{name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
will produce:
<root>my text</root>
while xsl:copy
will copy the element with its namespace preserved:
<root xmlns="htpp://www.example.com/my">my text</root>
EDIT
In response to comment by @parakmiakos:
Given the following input:
<my:root xmlns:my="htpp://www.example.com/my">my text</my:root>
this template*:
<xsl:template match="/*">
<xsl:element name="{name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
will produce:
<my:root xmlns:my="htpp://www.example.com/my">my text</my:root>
(*) provided that "my" prefix is declared in the stylesheet.
This template:
<xsl:template match="/*">
<xsl:element name="{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
will produce:
<root>my text</root>
and this one:
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
will return:
<my:root xmlns:my="htpp://www.example.com/my">my text</my:root>
same as the first one (but without having to declare the prefix).
Upvotes: 2
Reputation: 122364
The difference is apparent when you have namespace declarations in scope (other than the namespace of the element that you are copying). Using <xsl:copy>
will copy any in-scope namespace nodes, using <xsl:element>
won't. So given an input file of
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<foo/>
</root>
a stylesheet of
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates select="*/*" />
</xsl:template>
<xsl:template match="foo">
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
you will get output of
<?xml version="1.0"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
because <xsl:copy>
has copied the in-scope namespace nodes from the input element. Whereas if you use
<xsl:template match="foo">
<xsl:element name="{name()}" namespace="{namespace-uri()}"/>
</xsl:template>
you will get
<?xml version="1.0"?>
<foo/>
As Matthias points out, in XSLT 2.0 you can say <xsl:copy copy-namespaces="no">
to suppress the copying of in-scope namespaces - for an element node, <xsl:copy copy-namespaces="no">
has the same effect as <xsl:element name="{name()}" namespace="{namespace-uri()}">
Upvotes: 1