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

本文关键字:默认 空间 文档 何使用 Xslt 替换 Xml | 更新日期: 2023-09-27 18:13:14

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

我找到了一种简单的方法,但我仍然有一个错误,我不明白(这发生在。net框架4.5的XslCompiledTransform和Altova Xml Spy,但不是从notepad++的Xslt插件,例如):

这是输入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="urn:old.namespace"。我不明白为什么。

:

所以,我的预期结果是:
<?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替换Xml文档的默认名称空间

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

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解析器解析结果的目标应用程序都不应该能够分辨出这三个结果之间的区别。