【问题标题】:Copy all xml elements excluding matched element root name using xslt使用 xslt 复制所有 xml 元素,不包括匹配的元素根名称
【发布时间】:2015-08-12 17:28:10
【问题描述】:

输入 XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:VendorMessageRequest xmlns:ns2="http://order.com.company.com">
<ns2:purchaseOrder>     
<assignedTo>   
    <firstName>firstnm</firstName>
    <lastName>lstnm</lastName>
</assignedTo>
</ns2:purchaseOrder>
</ns2:VendorMessageRequest>

将 XSLT 用作:

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ns2="http://www.company.com/services/entity/v1"
                xmlns:ns3="http://www.company.com/services/dataobject/v1"
                 xmlns:ns4="http://order.com.company.com">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="ns4:purchaseOrder">
       <xsl:element name="ns3:someOtherPurchaseOrder" >
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                 </xsl:copy>
       </xsl:element>
    </xsl:template>
</xsl:stylesheet>

输出如下:

<?xml version="1.0" encoding="UTF-8"?>
<ns3:someOtherPurchaseOrder xmlns:ns3="http://www.company.com/services/dataobject/v1">
<ns2:purchaseOrder xmlns:ns2="http://order.com.company.com">
firstnmlstn</ns2:purchaseOrder>
</ns3:someOtherPurchaseOrder>

并期望输出 XML 为:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:someOtherPurchaseOrder xmlns:ns2="http://www.company.com/services/dataobject/v1">
  <assignedTo>
      <firstName>firstnm</firstName>
      <lastName>lstnm</lastName>
    </assignedTo>
</ns2:someOtherPurchaseOrder>

================= 我期待上面显示的 xml,其中匹配的元素名称(purchaseOrder)应该替换为其他名称(someOtherPurchaseOrder)。并且该匹配元素节点内的所有元素都应复制到更改的元素名称下。

即复制everthing并更改元素节点名称。

【问题讨论】:

  • 这是您使用的实际 XSLT 吗?您有一个 xsl:template 嵌套在另一个 xsl:template 中,这是不允许的,应该会导致错误。此外,如上一个问题中所述,命名空间是不同的。在您的 XML 中它是 http://order.com.company.com,但在您的 XSLT 中它是 http://order.com.company.com/,所以模板无论如何都不会匹配任何东西。是否可以编辑您的问题以更正此错误?谢谢!
  • @Tim:对不起,这是我的打字错误,我刚刚更改了问题。

标签: xml xslt xslt-1.0 transformation xml-namespaces


【解决方案1】:

在与purchaseOrder 匹配的模板中,您创建一个新元素,这是您需要的,但您也可以执行xsl:copy,这将复制现有的purchaseOrder 元素,这不是您需要的,因此您可以在此处删除xsl:copy

<xsl:template match="ns4:purchaseOrder">
   <xsl:element name="ns3:someOtherPurchaseOrder" >
        <xsl:apply-templates select="@*|node()"/>
   </xsl:element>
</xsl:template>

然后您执行xsl:apply-templates 来选择子项,这很好,但是您的XSLT 中没有任何其他模板可以匹配它们。这意味着将应用 XSLT 的内置模板,所有这些都会输出文本,而不是任何元素本身。

您可以通过将identity template 添加到您的 XSLT 来解决此问题

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

不过,这也会复制根 VendorMessageRequest 元素,因此您需要添加一个模板来跳过它。

试试这个 XSLT

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ns2="http://www.company.com/services/entity/v1"
                xmlns:ns3="http://www.company.com/services/dataobject/v1"
                 xmlns:ns4="http://order.com.company.com"
                 exclude-result-prefixes="ns2 ns4">

    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="ns4:VendorMessageRequest">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="ns4:purchaseOrder">
       <xsl:element name="ns3:someOtherPurchaseOrder" >
            <xsl:apply-templates select="@*|node()"/>
       </xsl:element>
    </xsl:template>
</xsl:stylesheet>

编辑:响应您的 cmets,如果您的输出中仍然存在未使用的命名空间声明,请尝试使用此 XSLT....

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ns2="http://www.company.com/services/entity/v1"
                xmlns:ns3="http://www.company.com/services/dataobject/v1"
                 xmlns:ns4="http://order.com.company.com"
                 exclude-result-prefixes="ns2 ns4">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*|node()[not(self::*)]">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ns4:VendorMessageRequest">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="ns4:purchaseOrder">
       <xsl:element name="ns3:someOtherPurchaseOrder" >
            <xsl:apply-templates select="@*|node()"/>
       </xsl:element>
    </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 效果很好。这里的一个问题是,命名空间已应用于所有子节点,这不是必需的。像 order.com.company.com"><firstName>firstnm</…>.... 因为,稍后我需要解组该 xml。
  • @David,尝试不使用copy-namespaces="no"
  • 我们已经在使用 。甚至我已经为 添加了。没有改善
  • xsltransform.net/eiZQaGf 是 Tim 的建议,结果是 &lt;ns3:someOtherPurchaseOrder xmlns:ns3="http://www.company.com/services/dataobject/v1"&gt; &lt;assignedTo&gt; &lt;firstName&gt;firstnm&lt;/firstName&gt; &lt;lastName&gt;lstnm&lt;/lastName&gt; &lt;/assignedTo&gt; &lt;/ns3:someOtherPurchaseOrder&gt; 看起来不错
  • 确实如此,但对我来说,它将命名空间应用于所有孩子,不知道为什么。同一个 xslt 中的其他 xsl 模板匹配会影响这个吗?
猜你喜欢
  • 2017-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多