【问题标题】:How to replace the default namespace of an Xml document using Xslt如何使用 Xslt 替换 Xml 文档的默认命名空间
【发布时间】:2015-12-14 12:31:03
【问题描述】:

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

我找到了一种简单的方法,但我仍然有一个我不明白的错误(例如,.Net framework 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>

请问,有人可以帮我吗?

【问题讨论】:

  • 您正在使用&lt;xsl:copy&gt; 复制范围内的命名空间,您需要将其替换为&lt;xsl:element name="{name()}" namespace="{namespace-uri()}"&gt;,但是这样会丢失xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
  • 你追求的结果是什么?
  • 我不希望将 urn:old.namespace 设置为 de DateTime 和 OffsetMinutes 节点上的默认命名空间。
  • 为什么要为此使用 XSLT?您可以使用简单的字符串操作轻松更改 xmlns=".." 声明的内容。
  • 你说得对,我就是这么说的。 Xslt 是应用程序需求的一部分,他们可以将它们放在一个文件夹中以动态更改 SOA 应用程序的输出。

标签: c# xml xslt


【解决方案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 解析器解析结果的目标应用程序都应该无法分辨这三个结果之间的差异。

【讨论】:

  • 您提供的第一个解决方案对我来说似乎更好:我们避免将未使用的旧命名空间 (xmlns="urn:old.namespace") 添加到节点,并将其他命名空间保留在根节点上(我将 de xmlns:i 作为测试,我的示例只是来自具有大量命名空间的更大 xml 的虚拟示例)
  • @XavierSteffen 我们只能使用您向我们展示的内容。 --附言如果您的问题得到解答,请通过接受答案来关闭它。
  • 你是对的。对此我深表歉意,我试图澄清,但这样做我失去了一些要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
相关资源
最近更新 更多