<xsl:copy>和<xsl:element name =“{name()}”>?</xsl:element> </xsl:copy>之间有什么区别吗?

时间:2014-02-10 12:18:42

标签: xml xslt

我想知道:

之间是否有任何区别
<xsl:template match="/*">
  <xsl:element name="{name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

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

3 个答案:

答案 0 :(得分:2)

至少有一个区别。鉴于以下输入:

<root xmlns="htpp://www.example.com/my">my text</root>

这个模板:

<xsl:template match="/*">
  <xsl:element name="{name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

将产生:

<root>my text</root>

xsl:copy将复制保留其名称空间的元素:

<root xmlns="htpp://www.example.com/my">my text</root>

修改
回应@parakmiakos的评论:

给出以下输入:

<my:root xmlns:my="htpp://www.example.com/my">my text</my:root>

此模板*:

<xsl:template match="/*">
  <xsl:element name="{name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

将产生:

<my:root xmlns:my="htpp://www.example.com/my">my text</my:root>

(*),前提是在样式表中声明了“my”前缀。

此模板:

<xsl:template match="/*">
  <xsl:element name="{local-name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

将产生:

<root>my text</root>

和这一个:

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

将返回:

<my:root xmlns:my="htpp://www.example.com/my">my text</my:root>

与第一个相同(但不必声明前缀)。

答案 1 :(得分:1)

xsl:element元素生成一个新的元素节点。

xsl:copy将上下文项复制到输出序列。但是,所述上下文项不必是元素节点。在你的情况下:

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

上下文项确实是一个元素。这会产生以下后果:

  • xsl:copy还复制元素的命名空间(如果有的话)
  • 如果上下文项是元素,则使用xsl:copy内的可选序列构造函数。在您的示例中,序列构造函数为<xsl:apply-templates/>

摘要xsl:copy可以复制任何类型的节点(原子值,文档,元素,文本,属性,处理指令,注释,命名空间),而xsl:element完全能够生成元素节点。

用法:使用xsl:copy有效地将节点从输入XML复制到输出序列。仅当元素名称为动态时才使用xsl:element,即事先未知。

另外,使用XSLT 2.0,您可以使用属性copy-namespacesinherit-namespaces明确控制名称空间的处理。

答案 2 :(得分:1)

当您在作用域中具有名称空间声明(除了要复制的元素的名称空间)时,差别很明显。使用<xsl:copy>将复制任何范围内的命名空间节点,而使用<xsl:element>则不会。所以给出了

的输入文件
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <foo/>
</root>

的样式表
<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>

您将获得

的输出
<?xml version="1.0"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />

因为<xsl:copy>已从input元素复制了范围内的命名空间节点。而如果你使用

  <xsl:template match="foo">
    <xsl:element name="{name()}" namespace="{namespace-uri()}"/>
  </xsl:template>

你会得到

<?xml version="1.0"?>
<foo/>

作为Matthias points out,在XSLT 2.0中,您可以说<xsl:copy copy-namespaces="no">来禁止复制范围内命名空间 - 对于元素节点,<xsl:copy copy-namespaces="no">具有与{{1}相同的效果}