'xsl:copy-of'不会复制节点

时间:2014-06-14 11:35:12

标签: xslt

我试图使用xslt来执行简单的地图。

首先,我定义一个指向我要复制的节点的变量,然后使用" xsl:copy-of select = $ var"

Ex. <xsl:variable name="myVar1" select="//cds/cd[@name='2']/node1/node2/addr2" />

这对于简单的测试xsl和test xml工作正常。但是对于实际的xml,它根本就不是复制节点。

测试xsl和实际的xsl之间的区别仅在于实际xsl中的节点名称实际上很长(需要应用它的xml具有长节点名称),并且测试xsl&amp; xml没有任何名称空间前缀。

如果我将变量仅指向根节点即<xsl:variable name="myVar1" select="//cds/cd[@name='2'],但我想将节点复制到该节点之下(即node1 / node2 / addr2)

我没有在xsl中看到任何错误(我使用XMLSpy),只是想知道在定义变量时是否对节点名称的长度有任何限制?

谢谢, 阿希什

更新

只是弄清楚导致问题的原因但不确定如何修复。是的,这些问题似乎与命名空间有关。当我在下面的示例xml中添加命名空间&#34; a&#34; 时,它停止工作(真正的xml有这样的命名空间)。

输入XML

<store>
    <cds>

    <cd  name="0">
            <test>this is test 0</test>
    </cd>

    <cd  name="1">      
        <node1 xmlns="anothernamespace">
            <node2 xmlns:a="http://someurl.com/something">
                <addr1>
                    <country>country1</country>
                </addr1>
                <addr2>
                    <state>state1</state>
                </addr2>
                <a:addr3>
                        <city>city1</city>
                        <phone>123</phone>              
                        <email>email1</email>
                        <website xmlns:b="somenamespace">
                            <b:name>website name</b:name>
                            <a:category>blog</a:category>
                        </website>                              
                </a:addr3>
            </node2>
        </node1>
    </cd>

    <cd  name="2">
            <test>this is test2</test>
    </cd>

</cds>
</store>

XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">

<xsl:variable name="myVar1" select="//cds/cd[@name='1']/node1/node2/addr3" />

    <addr>
    <xsl:copy-of select="$myVar1" />
    </addr>

</xsl:template>
</xsl:stylesheet>

如果xml没有名称空间&#34; a&#34;

,这样可以正常工作

2 个答案:

答案 0 :(得分:2)

首先,您需要在样式表中声明命名空间,为其分配前缀,并在寻址该命名空间中的节点时使用该前缀。

另一件事是,复制节点时,还要复制其命名空间。你没有发布你的预期结果,但我认为这不是你想要的。

另请注意,当您将节点(示例中为a:addr3)复制到另一个节点(addr)时,您将最终获得整个节点,包括启动和结束标记,嵌套在目标节点内。同样,我认为这不是你想要的。

尝试以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a="http://someurl.com/something"
exclude-result-prefixes="a">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
    <xsl:variable name="myVar1" select="//cds/cd[@name='1']/node1/node2/a:addr3" />
    <addr>
        <xsl:apply-templates select="$myVar1/*" mode="remove-ns"/>
    </addr>
</xsl:template>

<xsl:template match="*" mode="remove-ns">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="*" mode="remove-ns"/>
        <xsl:apply-templates select="@*|text()"/>
    </xsl:element>
</xsl:template>

<xsl:template match="@*">
    <xsl:copy/>
</xsl:template>

</xsl:stylesheet>

当应用于您的(相当奇怪的)示例输入时:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Edited by XMLSpy -->
<store>
    <cds>

    <cd  name="0">
            <test>this is test 0</test>
    </cd>

    <cd  name="1">      
        <node1>
            <node2 xmlns:a="http://someurl.com/something">
                <addr1>
                    <country>country1</country>
                </addr1>
                <addr2>
                    <state>state1</state>
                </addr2>
                <a:addr3>
                        <city>city1</city>
                        <phone>123</phone>              
                        <email>email1</email>
                        <website>
                            <name>website name</name>
                        </website>                              
                </a:addr3>
            </node2>
        </node1>
    </cd>

    <cd  name="2">
            <test>this is test2</test>
    </cd>

</cds>
</store> 

结果将是:

<addr>
   <city>city1</city>
   <phone>123</phone>
   <email>email1</email>
   <website>
      <name>website name</name>
   </website>
</addr>

编辑:

关于您的更新输入:

<store>
    <cds>

    <cd  name="0">
            <test>this is test 0</test>
    </cd>

    <cd  name="1">      
        <node1 xmlns="anothernamespace">
            <node2 xmlns:a="http://someurl.com/something">
                <addr1>
                    <country>country1</country>
                </addr1>
                <addr2>
                    <state>state1</state>
                </addr2>
                <a:addr3>
                        <city>city1</city>
                        <phone>123</phone>              
                        <email>email1</email>
                        <website xmlns:b="somenamespace">
                            <b:name>website name</b:name>
                            <a:category>blog</a:category>
                        </website>                              
                </a:addr3>
            </node2>
        </node1>
    </cd>

    <cd  name="2">
            <test>this is test2</test>
    </cd>

</cds>
</store>

这里的问题是节点继承其父节点的名称空间(除非它们被显式放入另一个名称空间)。在这里,您不仅需要考虑a:addr3的命名空间,还需要考虑a:addr3的祖先所有节点的命名空间:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ans="anothernamespace"
xmlns:a="http://someurl.com/something"
exclude-result-prefixes="ans a">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
    <xsl:variable name="myVar1" select="//cds/cd[@name='1']/ans:node1/ans:node2/a:addr3" />
    <addr>
        <xsl:apply-templates select="$myVar1/*" mode="remove-ns"/>
    </addr>
</xsl:template>

<xsl:template match="*" mode="remove-ns">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="*" mode="remove-ns"/>
        <xsl:apply-templates select="@*|text()"/>
    </xsl:element>
</xsl:template>

<xsl:template match="@*">
    <xsl:copy/>
</xsl:template>

</xsl:stylesheet>

请注意,模板本身没有变化 - 只更改了样式表命名空间声明和存储在$myVar1变量中的XPath。

答案 1 :(得分:1)

您需要在xslt的顶部定义'a'命名空间,然后在变量select中使用'a'添加前缀'addr3'。 它看起来如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a="http://someurl.com/something">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">

<xsl:variable name="myVar1" select="//cds/cd[@name='1']/node1/node2/a:addr3" />

<addr>
<xsl:copy-of select="$myVar1" />
</addr>

</xsl:template>
</xsl:stylesheet>