处理XML和XSLT中的默认命名空间的最佳解决方案

时间:2013-11-20 08:30:17

标签: xml xslt namespaces

如果您的输入XML中有一个默认命名空间,并且要完成XSLT转换,您只想在该命名空间中添加一个元素,那么您将如何做到这一点?

您是否将命名空间声明为XSLT中的默认命名空间?或者您是在XSLT中使用前缀,在XSLT中是否将所有元素都放入该命名空间中?

我创建了5个选项,其中一个选项错误,而其他4个选项都给出了正确的结果,但我只是想知道哪种方式最好,或者即使有更好的方法?

我使用下一个XML作为所有示例的输入:

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="http://example.org/uri/">
    <element attr="test">
        <one>This is an example</one>
        <two>Pretty nice</two>
    </element>
</data>

选项1,2&amp; 3

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:pref="http://example.org/uri/" exclude-result-prefixes="pref">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

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

        <added>Option 1</added>
        <xsl:element name="added" namespace="http://example.org/uri/">Option 2</xsl:element>
        <added xmlns="http://example.org/uri/">Option 3</added>
    </xsl:template>
</xsl:stylesheet>

将产生:

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="http://example.org/uri/">
    <element attr="test">
        <one>This is an example</one>
        <two>Pretty nice</two>
    </element>
    <added xmlns="">Option 1</added>
    <added>Option 2</added>
    <added>Option 3</added>
</data>

从上面的选项1中将不会创建正确的输出,因为在任何地方都没有声明默认命名空间。选项2和3将创建正确的输出,但如果我要添加多个元素,则XSLT看起来不太好,因为我需要在所有元素上添加命名空间。

在上面看一下你会说:我会在XSLT中添加一个默认命名空间,就像我在选项4中那样。

选项4

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://example.org/uri/" xmlns:pref="http://example.org/uri/" exclude-result-prefixes="pref">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

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

        <added>Option 4</added>
    </xsl:template>
</xsl:stylesheet>

这将产生:

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="http://example.org/uri/">
    <element attr="test">
        <one>This is an example</one>
        <two>Pretty nice</two>
    </element>
    <added>Option 4</added>
</data>

XSLT看起来更好,因为我不必在添加到XML的每个元素上声明命名空间。不知道为什么我应该或不应该这样做?当输入XML有两个不同的默认命名空间时,也许我会遇到问题?因此,有时我们会使用命名空间xmlns="http://example.org/uri/"并有时在命名空间xmlns="http://example.org/uriSecond/"中接收它。

选项5

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:pref="http://example.org/uri/" exclude-result-prefixes="pref">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

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

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

        <pref:added>Option 5</pref:added>
    </xsl:template>
</xsl:stylesheet>

将产生:

<?xml version="1.0" encoding="UTF-8"?>
<pref:data xmlns:pref="http://example.org/uri/">
    <pref:element attr="test">
        <pref:one>This is an example</pref:one>
        <pref:two>Pretty nice</pref:two>
    </pref:element><pref:added>Option 5</pref:added>
</pref:data>

同样正确的结果和所有元素都被重写为带前缀的命名空间。此外,XSLT中没有声明默认名称空间。如果我现在将收到具有不同默认命名空间的第二个输入,我也可以声明这个并复制带有该前缀的所有pref:模板。

所以我真的在寻找最好的解决方案,所以以后我不会遇到任何麻烦。或者所有工作解决方案都是一个好方法,但根据问题选择你的路径?

1 个答案:

答案 0 :(得分:1)

我认为选项4是最清楚的。

如果您必须在不同的模板中添加不同默认命名空间中的节点,那么您可以在3到4之间选择一些内容并在每个模板上放置xmlns="..."

<xsl:template match="ns1:something" xmlns="urn:ns1">
  <element1 />
  <element2 />
</xsl:template>

但是你的最后一段很好地总结了它 - 学习所有选项并使用在每种情况下最有意义的东西。