【问题标题】:Change namespace in XSLT with unknown prefix使用未知前缀更改 XSLT 中的命名空间
【发布时间】:2019-05-30 19:35:46
【问题描述】:

我想使用 XSLT 更改 XML 文件中的命名空间,仅基于 namespace-uri,而不知道这个命名空间定义了什么前缀。有可能吗?

我得到了一些解决方案,但是当我知道输入并且可以手动设置 xsl 文件时,它们仅适用于小文件。

我想要达到的目标:

输入 XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <re:rootElement xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:re="http://something.com/root"
xmlns:ns1="http://something.com/some/schema"
xmlns:cs2="http://something.com/another/schema"
xmlns:ns3="http://something.com/different/schema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<xsd:import namespace="http://something.com/another/schema" schemaLocation="/schema/location"/>

(下面有多个节点)

采用 2 个参数的 XSLT:

<xsl:param name="old_namespace" select="'http://something.com/another/schema'"/>
<xsl:param name="new_namespace" select="'http://something.com/another/schemaNEW'"/>

并输出为xml:

    <re:rootElement xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:re="http://something.com/root"
xmlns:ns1="http://something.com/some/schema"
xmlns:cs2="http://something.com/another/schemaNEW"
xmlns:ns3="http://something.com/different/schema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
 <xsd:import namespace="http://something.com/another/schemaNEW" schemaLocation="/schema/location"/>
(multiple nodes below)

【问题讨论】:

  • 1.对命名空间进行参数化有多重要?不能将它们硬编码在 XSLT 样式表中吗? -- 2. 你的处理器支持 XSLT 2.0 吗?
  • 1.这很重要,但现在作为一个快速解决方案,我想我会喜欢 xslt 2 中的硬编码版本。是的,我使用的是 Saxon 9
  • 请注意,您的输入不是格式正确的 XML,因为前缀 re 未绑定到命名空间。
  • 我确实纠正了这一点。我的错。
  • 在某个命名空间中很容易匹配和更改节点。对元素或属性值执行相同操作将需要使用模式感知 XSLT。或者您希望 XSLT 处理器如何知道 namespace 属性包含要更改的名称空间?您知道输入 XML 的结构、可能要更改的属性吗?

标签: xml xslt


【解决方案1】:

更改名称空间节点中使用的名称空间 URI 以及元素和属性的名称并不难。在模式感知样式表中,也可以(但可能更难)更改在 QName 类型的值中使用的命名空间 URI。我怀疑,更改出现的命名空间 URI 相当困难:

  • 直接在 xsi:schemaLocation 或 xs:import 等属性中(除非您枚举此类属性)

  • 在 NOTATION 的名称中

  • 在具有微语法的内容中,例如考虑

&lt;xsl:if test="namespace-uri() = 'http://old-namespace.com/'&gt;

如果它只是你所追求的元素和属性中使用的命名空间,那么你可以使用

<xsl:template match="*[namespace-uri()=$old-namespace]">
  <xsl:element name="{name()}" namespace="{$new-namespace}">
    <xsl:apply-templates select="@*, node()"/>
  </xsl:element>
</xsl:template>

<xsl:template match="@*[namespace-uri()='$old-namespace']">
  <xsl:attribute name="{name()}" namespace="{$new-namespace}" select="."/>
</xsl:template>

连同标识模板(或在 3.0 中,&lt;xsl:mode on-no-match="shallow-copy"/&gt;)一起确保其他元素和属性被原封不动地复制。

(这是 XSLT 2.0,但很容易在 1.0 中重写)。

【讨论】:

  • namespace-uri()='$old-namespace' 应该是 namespace-uri()=$old-namespace。而select="{.}" 就是select="."
  • 谢谢。它看起来很简单,但是当使用 saxon xsl 运行时,会删除输出 xml 文档中的所有标签。我这样使用它:gist.github.com/Tomasz9248/7e31d5f0c2d800e5dc558797d944f3ae
  • @Tomasz,您将需要使用身份转换作为起点,例如通过在 XSLT 3 中声明 &lt;xsl:mode on-no-match="shallow-copy"/&gt; 或在 XSLT 2 或 1 中包含模板 &lt;xsl:template match="@* | node()"&gt;&lt;xsl:copy&gt;&lt;xsl:apply-templates select="@* | node()"/&gt;&lt;/xsl:copy&gt;&lt;/xsl:template&gt;
  • 我做了,但仍然无法更改根元素中的命名空间 uri。
  • 那么您需要准确地告诉我们您在做什么以及它是如何失败的。可能最好开始一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-30
  • 1970-01-01
  • 2018-11-09
  • 2010-11-18
相关资源
最近更新 更多