使用xslt复制并重新排列XML节点



我有以下XML结构:

<root>
    <product>
        <name>  
            <book1>data for book1</book1>
            <book12>data for book12</book12>
            <book13>data for book13</book13>
            <book14>data for book14</book14>
        </name>
        <info>
            <data1>data for data1</data1>
            <data2>data for data2</data2>
            <data3>data for data3<data3>
            <data4>data for data4</data4>
            <data5>data for data5</data5>
            <data n+1>data n+1</data n+1>
        </info>
        <pictures>
            <pic1>data for pic1</pic1>
            <pic2>data for pic2</pic2>
            <pic3>data for pic3</pic3>
            <pic4>data for pic4</pic4>
            <pic n+1>data for pic n+1</pic n+1>
        </pictures>
    </product>
    <product>
    .
    .
    .
    .
    .
    </product>
    .
    .
    .
    .
</root>

现在,我需要在每个节点产品中复制data5、book14和整个节点图片,这样输出xml就会看起来像这样:

<root>
    <product>
        <node_that_i_would_name_1>
          <node_that_i_would_name_2>
            <node_that_i_would_name_3>
                <node_that_i_would_name_4>
                    <book14>data for book14</book14>
                </node_that_i_would_name_4>             
                <node_that_i_would_name_5>
                    <data5>data for data5</data5>
                </node_that_i_would_name_5>     
                <picturesA>
                    <pic1A>
                    <pic2A>
                    <pic3A>
                    <pic4A>
                    <pic n+1A>
                </picturesA>
                <empty_node_at_the_end_that_i_will_name></empty_node_at_the_end_that_i_will_name>
            </node_that_i_would_name_3>
          </node_that_i_would_name_2>
        </node_that_i_would_name_1>
        <name>  
            <book1>data for book1</book1>
            <book12>data for book12</book12>
            <book13>data for book13</book13>
            <book14>data for book14</book14>
        </name>
        <info>
            <data1>data for data1</data1>
            <data2>data for data2</data2>
            <data3>data for data3<data3>
            <data4>data for data4</data4>
            <data5>data for data5</data5>
            <data n+1>data n+1</data n+1>
        </info>
        <pictures>
            <pic1>data for pic1</pic1>
            <pic2>data for pic2</pic2>
            <pic3>data for pic3</pic3>
            <pic4>data for pic4</pic4>
            <pic n+1>data for pic n+1</pic n+1>
        </pictures>
    </product>
    <product>
    .
    .
    .
    .
    .
    </product>
    .
    .
    .
    .
</root>

每件事都应该保持不变,只有这些数据必须以上面的方式复制和重新排列到节点中。使用xslt有简单的方法吗?

当您看到这样的问题时,您的第一个想法应该是Identity Transform

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

所有这一切本身只是简单地将所有现有节点复制到输出文档中。但这意味着,您只需要为任何想要转换的特定元素编写模板,在您的情况下是product元素。(XSLT将优先考虑与特定节点名称匹配的模板,而不是标识模板使用的更通用的匹配)。

因此,产品的模板将具有此结构。本质上,它仍然是身份转换,但添加了额外的代码

<xsl:template match="product">
   <xsl:copy>
      <xsl:apply-templates select="@*" />
      <!-- Code to create new nodes and create extra copies of existing ones goes here -->
      <xsl:apply-templates select="node()"/>
  </xsl:copy>

编辑:请注意,在任何元素之前都需要复制属性!

例如,要在新元素中创建book14元素的副本,只需添加以下代码:

 <newnode1>
   <xsl:apply-templates select="name/book14"/>
 </newnode1>  

对于图片元素,为了允许在元素名称上添加额外后缀来复制,您需要一个模板来匹配子元素,并使用一个(可选)参数来创建元素名称

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

然后,这个模板将在两个不同的地方使用。一个是它与结构正常匹配的地方,另一个是你想创建额外副本的地方。但在后一种情况下,您将设置参数:

<xsl:apply-templates select="pictures/*">
   <xsl:with-param name="suffix" select="'A'" />
</xsl:apply-templates>

尝试将此XSLT作为一个示例,您应该能够使用那些您真正想要命名的节点来扩展它。。。。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="product">
      <xsl:copy>
         <xsl:apply-templates select="@*"/>
         <newnode>
            <newnode1>
               <xsl:apply-templates select="name/book14"/>
            </newnode1>
            <newnode2>
               <xsl:apply-templates select="info/data5"/>
            </newnode2>
            <picturesA>
               <xsl:apply-templates select="pictures/*">
                  <xsl:with-param name="suffix" select="'A'" />
               </xsl:apply-templates>
            </picturesA>
         </newnode>
         <xsl:apply-templates select="node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="pictures/*">
      <xsl:param name="suffix" />
      <xsl:element name="{concat(local-name(), $suffix)}">
         <xsl:apply-templates select="@*|node()"/>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

最新更新