【问题标题】:replace namespace prefix and add attributes using XSLT使用 XSLT 替换命名空间前缀并添加属性
【发布时间】:2015-07-28 16:05:05
【问题描述】:

假设我有以下 XML 作为源:

<ns0:msg xmlns:ns0="namespace0">
    <ns0:hdr a_lot_of_attrs="value">
some nodes...
</ns0:hdr>
    <ns0:body>
        <ns0:data a_lot_of_attrs="value">
            <ns1:purchase_order xmlns:ns1="namespace1">some nodes...</ns1:purchase_order>
        </ns0:data>
    </ns0:body>
</ns0:msg>

我需要以下 XML 作为结果:

    <a:msg xmlns:a="namespace0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <a:hdr a_lot_of_attrs="value">
    some nodes...
    </a:hdr>
        <a:body>
            <a:data a_lot_of_attrs="value">
                <b:purchase_order 
 xsi:schemaLocation="filelocation"
xmlns:b="namespace1"  
xmlns:c="namespace2">some nodes...</b:purchase_order>
            </a:data>
        </a:body>
    </a:msg>

基本上我只需要将命名空间前缀 ns0 替换为 a 并将 ns1 替换为 b。此外,根元素&lt;a:msg&gt; 以及&lt;b:purchase_order&gt; 需要添加一些附加属性。

我的尝试是使用以下 XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="namespace0" 
xmlns:ns1="namespace1" 
xmlns:a="namespace0" 
xmlns:b="namespace1" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
exclude-result-prefixes="ns0 ns1">

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

    <xsl:template match="/">
        <a:msg xmlns:msg="namespace1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <xsl:copy>
                <xsl:apply-templates select="ns0:msg/*"/>
            </xsl:copy>
        </a:msg>
    </xsl:template>

    <xsl:template match="/ns0:msg/ns0:body/ns0:data/ns1:purchase_order">
        <b:purchase_order xsi:schemaLocation="filelocation" xmlns:c="namespace2">
            <xsl:copy>
                <xsl:apply-templates select="node()"/>
            </xsl:copy>
        </b:purchase_order>
    </xsl:template>

    <xsl:template match="ns0:*">
        <xsl:element name="a:{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="ns1:*">
        <xsl:element name="b:{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="@*">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

到目前为止,它工作正常,除了节点 &lt;purchase_order&gt; 已被填充 2 次:

<a:msg xmlns:a="namespace0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <a:hdr a_lot_of_attrs="value">
some nodes...
</a:hdr>
    <a:body>
        <a:data a_lot_of_attrs="value">
            <b:purchase_order xmlns:b="namespace1" xmlns:c="namespace2" xsi:schemaLocation="filelocation">
                <ns1:purchase_order xmlns:ns0="namespace0" xmlns:ns1="namespace1">some nodes...</ns1:purchase_order>
            </b:purchase_order>
        </a:data>
    </a:body>
</a:msg>

我通过调整第二个&lt;xsl:template&gt; 尝试了几次,但无法正确。有人可以告诉我这里哪里出错了,我该如何完成?

非常感谢。

【问题讨论】:

  • "我只需要将命名空间前缀 ns0 替换为 a 并将 ns1 替换为 b。" 为什么需要这样做?命名空间前缀没有意义。只要命名空间 URI 相同,输出在语义上就与输入相同。
  • 嗨,迈克尔,我完全同意你的看法:前缀毫无意义。然而,负责 xml 解析器的人不知何故编写了一些奇怪的程序,这些程序需要特定的前缀,他不愿意更改它。这就是为什么我需要做出妥协并自己创建一个 xslt。

标签: xslt namespaces


【解决方案1】:

ns1:purchase_order 匹配的当前模板包含xsl:copy 以及新b:purchase_order 的创建。因此,您正在复制旧节点并创建一个新节点。

您可以从模板中删除xsl:copy,如下所示:

<xsl:template match="ns1:purchase_order">
    <b:purchase_order xsi:schemaLocation="filelocation" xmlns:c="namespace2">
        <xsl:apply-templates select="node()"/>
    </b:purchase_order>
</xsl:template>

请注意,您不必在模板匹配中指定完整路径。只有当您在 XML 中有第二个 ns1:purchase_order 时,您才真正需要这样做,在不同的位置,您不想匹配。

【讨论】:

  • 太好了,效果很好,非常感谢您的更正和建议。对我这样的初学者很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
  • 2013-11-02
相关资源
最近更新 更多