1

我们有一个生成不需要的 XML 元素的工具,我们正在使用 XSLT 将其转换为所需的格式。

我们正在为文件生成的每个 XML 编写不同的 XSLT。例如,一个用于客户 XML,一个用于订单 XML,以此类推。

下面是该工具生成的几个 XML 数据文件和预期的实际输出

顾客

工具生成的 XML

<Message>
  <Data>
    <CustomerArray>
      <Customer>
        <X>
          <Name>John</Name>
          <Id>100</Id>
          <Roles>
            <Role>
              <X>Manager</X>
              <X>Architect</X>
            </Role>
          </Roles>
        </X>
        <X>
          <Name>Doe</Name>
          <Id>102</Id>
          <Roles>
            <Role>
              <X>Supervisor</X>
              <X>Admin</X>
            </Role>
          </Roles>
        </X>
      </Customer>
    </CustomerArray>
  </Data>
</Message>

所需的 XML 数据

<Message>
  <Data>
    <CustomerArray>
      <Customer>
        <Name>John</Name>
        <Id>100</Id>
        <Roles>
          <Role>Manager</Role>
          <Role>Architect</Role>
        </Roles>
      </Customer>
      <Customer>
        <Name>Doe</Name>
        <Id>102</Id>
        <Roles>
          <Role>Supervisor</Role>
          <Role>Admin</Role>
        </Roles>
      </Customer>
    </CustomerArray>
  </Data>
</Message>

订单

工具生成的 XML

<Message>
  <Orders>
    <Order>
      <X>
        <OrderNumber>O123</OrderNumber>
        <CustomerID>C100</CustomerID>
        <Quantity>100</Quantity>
        <UnitPrice>10.0</UnitPrice>
      </X>
      <X>
        <OrderNumber>O456</OrderNumber>
        <CustomerID>C107</CustomerID>
        <Quantity>100</Quantity>
        <UnitPrice>5.0</UnitPrice>
      </X>
    </Order>
  </Orders>
</Message>

所需的 XML 数据

<Message>
  <Orders>
    <Order>
      <OrderNumber>O123</OrderNumber>
      <CustomerID>C100</CustomerID>
      <Quantity>100</Quantity>
      <UnitPrice>10.0</UnitPrice>
    </Order>
    <Order>
      <OrderNumber>O456</OrderNumber>
      <CustomerID>C107</CustomerID>
      <Quantity>100</Quantity>
      <UnitPrice>5.0</UnitPrice>
    </Order>
  </Orders>
</Message>

不需要的元素X可以出现在任何级别。

是否可以编写一个通用的 XSLT 转换来在所有 XML 输入中实现这个结果?例如,在X找到 an 的地方,将其替换为父标签,然后删除父标签。

4

2 回答 2

2

您需要为具有任何子节点的所有节点编写一个带有显式模板的身份转换,X以便可以复制它们。

此转换可以满足您的要求。它使用变量name来保存作为父元素的名称,X以避免在name(current())生成每个输出元素时写得更晦涩。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:strip-space elements="*"/>
  <xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>

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

  <xsl:template match="*[X]">
    <xsl:variable name="name" select="name()"/>
    <xsl:for-each select="X">
      <xsl:element name="{$name}">
        <xsl:apply-templates/>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

输出

顾客

<Message>
   <Data>
      <CustomerArray>
         <Customer>
            <Name>John</Name>
            <Id>100</Id>
            <Roles>
               <Role>Manager</Role>
               <Role>Architect</Role>
            </Roles>
         </Customer>
         <Customer>
            <Name>Doe</Name>
            <Id>102</Id>
            <Roles>
               <Role>Supervisor</Role>
               <Role>Admin</Role>
            </Roles>
         </Customer>
      </CustomerArray>
   </Data>
</Message>

订单

<Message>
   <Orders>
      <Order>
         <OrderNumber>O123</OrderNumber>
         <CustomerID>C100</CustomerID>
         <Quantity>100</Quantity>
         <UnitPrice>10.0</UnitPrice>
      </Order>
      <Order>
         <OrderNumber>O456</OrderNumber>
         <CustomerID>C107</CustomerID>
         <Quantity>100</Quantity>
         <UnitPrice>5.0</UnitPrice>
      </Order>
   </Orders>
</Message>
于 2013-05-15T01:49:35.973 回答
1

这是一个稍微简单/较短的解决方案,它也可以正确处理 aX可以有非X兄弟元素的情况:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="*[X]"><xsl:apply-templates/></xsl:template>

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

当此转换应用于以下 XML 文档(提供的第一个文档,将一个非X同级元素添加到X元素中时:

<Message>
  <Data>
    <CustomerArray>
      <Customer>
        <X>
          <Name>John</Name>
          <Id>100</Id>
          <Roles>
            <Role>
              <X>Manager</X>
              <X>Architect</X>
            </Role>
          </Roles>
        </X>
        <somethingElse/>
        <X>
          <Name>Doe</Name>
          <Id>102</Id>
          <Roles>
            <Role>
              <X>Supervisor</X>
              <X>Admin</X>
            </Role>
          </Roles>
        </X>
      </Customer>
    </CustomerArray>
  </Data>
</Message>

产生了想要的正确结果

<Message>
   <Data>
      <CustomerArray>
         <Customer>
            <Name>John</Name>
            <Id>100</Id>
            <Roles>
               <Role>Manager</Role>
               <Role>Architect</Role>
            </Roles>
         </Customer>
         <somethingElse/>
         <Customer>
            <Name>Doe</Name>
            <Id>102</Id>
            <Roles>
               <Role>Supervisor</Role>
               <Role>Admin</Role>
            </Roles>
         </Customer>
      </CustomerArray>
   </Data>
</Message>

请注意,鲍罗丁的解决方案失去了somethingElse元素。

于 2013-05-15T03:42:39.093 回答