如何消除由一个XML文档的XSLT转换生成的xmlns =“”条目到另一个XML文档

时间:2009-12-04 02:15:32

标签: xslt namespaces xml-namespaces

好的,我在这个问题上看到了很多变化,但没有一个完全回答我想要解决的问题,也许我只是太过密集而无法看到如何将其他答案应用于我正在尝试的内容要做。

我有一些类似于以下内容的XML:

<?xml version="1.0" encoding="utf-8"?>
<message>
  <cmd id="api_info">
    <api-version>1.0</api-version>
    <api-build>1.0.0.0</api-build>
  </cmd>
</message>

现在我有一个XSLT转换,我正在申请这个XML。 XSLT类似于以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:fn="http://www.w3.org/2005/xpath-functions"
                version="2.0">

    <xsl:output method="xml" version="1.0" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="message"/>
    </xsl:template>

    <xsl:template match="message">
        <xsl:element name="message" xmlns="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="/message/cmd/@id">
        <xsl:variable name="_commandType" select="/message/cmd/@id"/>
        <xsl:element name="messageHeader">
            <xsl:element name="cmdType">
                <xsl:value-of select="$_commandType"/>
            </xsl:element>
        </xsl:element>

        <xsl:element name="messageBody">
            <xsl:choose>
                <xsl:when test="$_commandType = 'api_info'">
                    <xsl:element name="apiInfoBody">
                        <xsl:element name="apiVersion">
                            <xsl:value-of select="/message/cmd/api-version"/>
                        </xsl:element>
                        <xsl:element name="apiBuild">
                            <xsl:value-of select="/message/cmd/api-build"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
                <xsl:when test="$_commandType = 'communicationError'">
                    <xsl:element name="communicationErrorBody">
                        <xsl:element name="errorCode">
                            <xsl:value-of select="error-code"/>
                        </xsl:element>
                        <xsl:element name="badCmd">
                            <xsl:value-of select="bad-cmd"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

我得到的输出基本上是我想要的,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns="http://www.companyname.com/schemas/product/Version001">
    <messageHeader xmlns="">
        <cmdType>api_info</cmdType>
    </messageHeader>
    <messageBody xmlns="">
        <apiInfoBody>
            <apiVersion>1.0</apiVersion>
            <apiBuild>1.0.0.0</apiBuild>
        </apiInfoBody>
    </messageBody>
</message>

但我不想要的是&lt; messageHeader&gt; &lt; messageBody&gt; 元素中的 xmlns =“”属性

现在我发现,如果我在XSLT中为这些元素显式指定了命名空间,那么不需要的属性会被压缩到这些属性的子级别。

我可以浏览整个XSLT并明确地将 xmlns =“”http://www.companyname.com/schemas/product/Version001属性添加到我的每个 xsl:element 定义中,但是我知道必须有一种更优雅的方式。我们的程序员懒得没有这种废话的捷径。如果我的XSLT不是简单的缩写示例,我很想做到这一点那样。但我知道必须有更好的方法。

有谁知道我在这里缺少什么?

谢谢,

AlarmTripper

3 个答案:

答案 0 :(得分:9)

在xsl:stylesheet标记上使用带有前缀“#default”

的exclude-result-prefixes

w3c中的引用为HERE

编辑:好的,我应该更仔细地研究你的XSL。将消息标记上的xmlns移动到样式表标记。这会将所有结果元素放在同一名称空间中,并在消息标记上生成一个名称空间属性。我在Oxygen / XML中运行它并得到你想要的输出。

答案 1 :(得分:0)

好的,我明白了。

我想要的XSLT看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:fn="http://www.w3.org/2005/xpath-functions"
                exclude-result-prefixes="xsl fo xs fn">

    <xsl:output method="xml" version="1.0" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="message"/>
    </xsl:template>

    <xsl:template match="message">
        <message namespace="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </message>
    </xsl:template>

    <xsl:template match="/message/cmd/@id">
        <xsl:variable name="_commandType" select="/message/cmd/@id"/>

        <xsl:element name="messageHeader">
            <xsl:element name="cmdType">
                <xsl:value-of select="$_commandType"/>
            </xsl:element>
        </xsl:element>

        <xsl:element name="messageBody">
            <xsl:choose>
                <xsl:when test="$_commandType = 'api_info'">
                    <xsl:element name="apiInfoBody">
                        <xsl:element name="apiVersion">
                            <xsl:value-of select="/message/cmd/api-version"/>
                        </xsl:element>
                        <xsl:element name="apiBuild">
                            <xsl:value-of select="/message/cmd/api-build"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
                <xsl:when test="$_commandType = 'communicationError'">
                    <xsl:element name="communicationErrorBody">
                        <xsl:element name="errorCode">
                            <xsl:value-of select="error-code"/>
                        </xsl:element>
                        <xsl:element name="badCmd">
                            <xsl:value-of select="bad-cmd"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

修正它的更改是将排除结果前缀属性添加到&lt; xsl:stylesheet&gt; 元素并更改以下部分:

    <xsl:template match="message">
        <xsl:element name="message" xmlns="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </xsl:element>
    </xsl:template>

取而代之的是:

    <xsl:template match="message">
        <message namespace="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </message>
    </xsl:template>

现在我又开心了。

可能有更好的方法,但这对我有用。任何未来的建议仍然受到欢迎。

答案 2 :(得分:0)

吉姆加里森的(更新的)答案是你应该需要的。但是你发布的更新样式表在结果中输出了一个“命名空间”属性,所以我不确定你有什么好处。

要理解的关键是默认命名空间的工作原理。不要将xmlns视为可以输出到结果的属性。相反,将其视为样式表的词法细节,其目的是为其下面的所有内容设置默认命名空间(元素本身及其后代中的每一个,直到被覆盖)。 (反过来,它在结果XML中具有相同的功能,它具有与样式表本身非常不同的结构。)

样式表中的文字结果元素(例如&lt; message&gt;)以及&lt; xsl:element&gt;当提供的名称不使用前缀时,指令(例如,&lt; xsl:element name =“message”&gt;)都采用默认命名空间。如果你希望所有都使用相同的命名空间,那么你需要在样式表的顶部放置一个默认的命名空间,正如Jim Garrison建议的那样。

否则,您最终会得到一些不在该命名空间中的元素,这就是为什么结果包含xmlns =“”(取消设置这些元素的命名空间)。