使用xslt复制和重新排列XML节点 [英] Copy and rearrange XML nodes with xslt

查看:57
本文介绍了使用xslt复制和重新排列XML节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下XML结构:

i have folowing XML structure:

<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看起来像这样:

Now i would need to copy data5, book14 and whole node pictures within every node product so output xml would look like this:

<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做到这一点?

Every thing should stay the same, only this data would have to be copyed and rearenged in way above into nodes. Is there simple way to do this with xslt?

推荐答案

当您遇到这样的问题时,您首先想到的应该是

When you ever see a problem like this, your first thought should be the Identity Transform

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

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

All this does by itself is simply copy all existing nodes to the output document. But what this means is that you then only have to write templates for any particular element you wish to transform, in your case the product element. (XSLT will give priority to templates that match a specific node name over the more generic match used by the identity template).

因此,产品的模板将具有此结构.从本质上讲,它仍然是身份转换,但附带了额外的代码.

So, the template for product would have this structure. Essentially it is still the identity transform but with extra code thrown in.

<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>

请注意,必须在所有元素之前复制属性!

Note that attributes need to be copied across before any elements!

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

For example, to create a copy of the book14 element within a new element, you would simply add this code:

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

对于Picture元素,要允许复制带有元素名称后缀的后缀,您将拥有一个模板来匹配子元素,并带有一个(可选)参数,该参数随后将用于创建元素名称

For the Picture elements, to allow this to be copied with an extra suffix on the element name, you would have a template to match the child elements, with an (optional) parameter which would then be used in creating the element name

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

此模板将在两个不同的地方使用.一种在正常情况下与结构匹配,另一种在您要创建额外副本的位置.但是在后一种情况下,您可以设置参数:

This template would then be used in two different places. One where it matches the structure normally, and one where you want to create the extra copy. But in the latter case, you would set the parameter:

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

尝试使用此XSLT作为示例,您应该可以使用您真正想为自己命名的节点进行扩展....

Try this XSLT as a sample, you should be able to expand on it with those nodes that you really want to name yourself....

<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>

这篇关于使用xslt复制和重新排列XML节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆