如何使用Xslt替换Xml文档的默认命名空间

时间:2015-09-17 15:02:15

标签: c# xml xslt

我是xslt的新手,我收到了一个简单的请求:使用Xslt(1.0,我不能使用2.0)将xml文档中的默认xml命名空间替换为另一个命名空间。 / p>

我找到了一种简单的方法,但我仍然有一个我不明白的错误(来自.Net framework 4.5和Altova Xml Spy的XslCompiledTransform,而不是来自的Xslt插件)例如Notepad ++):

这是输入Xml:

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:old.namespace">
    <Companies>
        <Company>
            <AuditedOn xmlns:d4p1="http://schemas.datacontract.org/2004/07/System">
                <d4p1:DateTime>2012-10-08T13:34:04.04Z</d4p1:DateTime>
                <d4p1:OffsetMinutes>0</d4p1:OffsetMinutes>
            </AuditedOn>
            <Name>CompanyNameTest</Name>
        </Company>
        <Company>
            <AuditedOn xmlns:d6p1="http://schemas.datacontract.org/2004/07/System">
                <d6p1:DateTime>2012-10-08T13:34:04.04Z</d6p1:DateTime>
                <d6p1:OffsetMinutes>0</d6p1:OffsetMinutes>
            </AuditedOn>
            <Name>CompanyNameTest2</Name>
        </Company>
    </Companies>
</Test>

我的Xslt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:previous="urn:old.namespace" >

   <xsl:output encoding='UTF-8' indent='yes' method='xml'/>

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

  <!-- Previous namespace -> current. No other changes required. -->
  <xsl:template match='previous:*'>
    <xsl:element name='{local-name()}'
                 namespace='urn:new.namespace'>
      <xsl:copy-of select='namespace::*[not(. = namespace-uri(current()))]' />
      <xsl:apply-templates select='@* | node()' />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="urn:new.namespace" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Companies>
        <Company>
            <AuditedOn xmlns:d4p1="http://schemas.datacontract.org/2004/07/System">
                <d4p1:DateTime xmlns="urn:old.namespace">2012-10-08T13:34:04.04Z</d4p1:DateTime>
                <d4p1:OffsetMinutes xmlns="urn:old.namespace">0</d4p1:OffsetMinutes>
            </AuditedOn>
            <Name>CompanyNameTest</Name>
        </Company>
        <Company>
            <AuditedOn xmlns:d6p1="http://schemas.datacontract.org/2004/07/System">
                <d6p1:DateTime xmlns="urn:old.namespace">2012-10-08T13:34:04.04Z</d6p1:DateTime>
                <d6p1:OffsetMinutes xmlns="urn:old.namespace">0</d6p1:OffsetMinutes>
            </AuditedOn>
            <Name>CompanyNameTest2</Name>
        </Company>
    </Companies>
</Test>

如您所见,在AuditedOn节点(这是一个DateTimeOffset对象)上,转换集再次设置xmlns =&#34; urn:old.namespace&#34;在每个节点上。我不明白为什么。

更新

所以,我的预期结果是:

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="urn:new.namespace" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Companies>
    <Company>
        <AuditedOn xmlns:d4p1="http://schemas.datacontract.org/2004/07/System">
            <d4p1:DateTime>2012-10-08T13:34:04.04Z</d4p1:DateTime>
            <d4p1:OffsetMinutes>0</d4p1:OffsetMinutes>
        </AuditedOn>
        <Name>CompanyNameTest</Name>
    </Company>
    <Company>
        <AuditedOn xmlns:d6p1="http://schemas.datacontract.org/2004/07/System">
            <d6p1:DateTime>2012-10-08T13:34:04.04Z</d6p1:DateTime>
            <d6p1:OffsetMinutes>0</d6p1:OffsetMinutes>
        </AuditedOn>
        <Name>CompanyNameTest2</Name>
    </Company>
</Companies>
</Test>

拜托,有人可以帮帮我吗?

1 个答案:

答案 0 :(得分:1)

我相信这会产生你正在寻找的结果(你忽略了提供):

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:previous="urn:old.namespace">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- old namespace -> new -->
<xsl:template match="previous:*">
    <xsl:element name="{local-name()}" namespace="urn:new.namespace">
        <xsl:copy-of select="namespace::*[not(. = 'urn:old.namespace')]" />
        <xsl:copy-of select="@*" />
        <xsl:apply-templates select="node()" />
    </xsl:element>
</xsl:template>

<!-- instead of identity transform template -->
<xsl:template match="*">
    <xsl:element name="{name()}" namespace="{namespace-uri()}">
        <xsl:copy-of select="@*" />
        <xsl:apply-templates select="node()" />
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

<强>结果

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="urn:new.namespace" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
   <Companies>
      <Company>
         <AuditedOn xmlns:d4p1="http://schemas.datacontract.org/2004/07/System">
            <d4p1:DateTime>2012-10-08T13:34:04.04Z</d4p1:DateTime>
            <d4p1:OffsetMinutes>0</d4p1:OffsetMinutes>
         </AuditedOn>
         <Name>CompanyNameTest</Name>
      </Company>
      <Company>
         <AuditedOn xmlns:d6p1="http://schemas.datacontract.org/2004/07/System">
            <d6p1:DateTime>2012-10-08T13:34:04.04Z</d6p1:DateTime>
            <d6p1:OffsetMinutes>0</d6p1:OffsetMinutes>
         </AuditedOn>
         <Name>CompanyNameTest2</Name>
      </Company>
   </Companies>
</Test>

补充说明:

以上内容可以简化为:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<!-- old namespace -> new -->
<xsl:template match="*[namespace-uri() = 'urn:old.namespace']">
    <xsl:element name="{local-name()}" namespace="urn:new.namespace">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

这里的结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="urn:new.namespace">
   <Companies>
      <Company>
         <AuditedOn>
            <d4p1:DateTime xmlns:d4p1="http://schemas.datacontract.org/2004/07/System" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:old.namespace">2012-10-08T13:34:04.04Z</d4p1:DateTime>
            <d4p1:OffsetMinutes xmlns:d4p1="http://schemas.datacontract.org/2004/07/System" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:old.namespace">0</d4p1:OffsetMinutes>
         </AuditedOn>
         <Name>CompanyNameTest</Name>
      </Company>
      <Company>
         <AuditedOn>
            <d6p1:DateTime xmlns:d6p1="http://schemas.datacontract.org/2004/07/System" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:old.namespace">2012-10-08T13:34:04.04Z</d6p1:DateTime>
            <d6p1:OffsetMinutes xmlns:d6p1="http://schemas.datacontract.org/2004/07/System" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:old.namespace">0</d6p1:OffsetMinutes>
         </AuditedOn>
         <Name>CompanyNameTest2</Name>
      </Company>
   </Companies>
</Test>

此结果在语义上与另一个结果相同。差异仅仅是装饰性的:

  • 名称空间声明 xmlns:i="http://www.w3.org/2001/XMLSchema-instance"已被移动 并且(不必要地)复制到其他元素 - 但是,这个 声明无论如何都是多余的,所以它在哪里都无所谓 出现,或者如果出现的话;

  • 某些元素将默认命名空间声明为 xmlns="urn:old.namespace" - 然而,实际上没有元素 放在此命名空间

同样,您在问题中报告的结果在语义上也与上述两个相同xmlns="urn:old.namespace"的冗余默认命名空间声明就是:冗余。整个结果中的任何节点实际上都没有放在此命名空间中。

使用符合标准的XML解析器解析结果的任何目标应用程序都不应该能够区分这三个结果。