递归XSLT转换

时间:2013-05-07 07:18:30

标签: xml xslt

然而又是一个有问题的任务。我有一个不太好的xml。例如以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<Values>
<record name='svc_sig'>
<record name="sig_in">
    <array depth="1" name="rec_fields" type="record">
        <record>
            <!-- Some irrelevant metadata information with value node name... -->
            <value name="field_name">docTest</value>
            <value name="field_type">record</value>
            <value name="field_dim">0</value>
            <array depth="1" name="rec_fields" type="record">
                <record javaclass="com.wm.util.Values">
                    <!-- Some irrelevant metadata information with value node name... -->
                    <value name="field_name">doc.name</value>
                    <value name="field_type">string</value>
                    <value name="field_dim">0</value>
                </record>
            </array>
        </record>
        <record>
            <value name="field_name">docListTest</value>
            <value name="field_type">record</value>
            <value name="field_dim">1</value>
            <array depth="1" name="rec_fields" type="record">
                <record>
                    <value name="field_name">d0</value>
                    <value name="field_type">record</value>
                    <value name="field_dim">0</value>
                    <array depth="1" name="rec_fields" type="record">
                        <record>
                            <value name="field_name">d0.name</value>
                            <value name="field_type">string</value>
                            <value name="field_dim">0</value>
                        </record>
                    </array>
                </record>
            </array>
        </record>
        <record>
            <value name="field_name">packages_should_work</value>
            <value name="field_type">recref</value>
            <value name="field_dim">0</value>
            <value name="rec_ref">data:packages</value>
        </record>
        <record>
            <value name="field_name">packages_list_should_work</value>
            <value name="field_type">recref</value>
            <value name="field_dim">1</value>
            <value name="rec_ref">data:packages</value>
        </record>
    </array>
</record>
</record>
</Values>

为简单起见,我需要将此xml映射到已经给出的java类,我无法更改它。考虑到这一点,我必须将这个xml转换为具有有意义名称的另一个xml。例如:

<sig_in>
   <record>
      <field_name>docTest</field_name>
      <field_type>record</field_type>
      <field_dim>0</field_dim>
   </record>
   <record>
      <field_name>docListTest</field_name>
      <field_type>record</field_type>
      <field_dim>1</field_dim>
   </record>
   <record>
      <field_name>packages_should_work</field_name>
      <field_type>recref</field_type>
      <field_dim>0</field_dim>
   </record>
   <record>
      <field_name>packages_list_should_work</field_name>
      <field_type>recref</field_type>
      <field_dim>1</field_dim>
   </record>
</sig_in>

到目前为止,我创建了这样的东西:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8" />
    <xsl:template match="/" name="service_signature">
        <sig_in>
            <xsl:for-each select="Values/record[@name='svc_sig']/record[@name='sig_in']/array[@name]/record">
                <record>
                    <field_name><xsl:value-of select="value[@name='field_name']/text()"/></field_name>
                    <field_type><xsl:value-of select="value[@name='field_type']/text()"/></field_type>
                    <field_dim><xsl:value-of select="value[@name='field_dim']/text()"/></field_dim>
                </record>
            </xsl:for-each>
        </sig_in>
    </xsl:template>

</xsl:stylesheet>

虽然它适用于主要元素但不适用于嵌套记录。我可以创建一个xsl:for-each并迭代每个项目,如果类型是记录,但这不会解决太多;因为它可以是任何深层次的。我知道我应该使用递归我只是无法想象我怎么能在这种特殊情况下做到。

@Edit - 对嵌套类型的一些修正:

<record>
  <field_name>docListTree</field_name>
  <field_type>record</field_type>
  <field_dim>1</field_dim>
  <record>
    <field_name>d0</field_name>
    <field_type>record</field_type>
    <field_dim>0</field_dim>
    <record>
      <field_name>d0.name</field_name>
      <field_type>string</field_type>
      <field_dim>0</field_dim>
    </record>
  </record>
</record>

因此,您可以看到原始类型嵌套的位置,我也需要在生成的xml中使用相同的内容。或者在公寓中,我需要在父节点和子节点中使用一些唯一的标识符,因此我知道哪个包含哪个。在任何方面我都不应该松开结构。

@Edit:   - 真的很抱歉我想节省空间,但我没有展示墙后的复杂性。所以每条记录都包含值名称节点。其中大多数只包含我不需要的无用的元数据信息。还有两个记录,@ name {sig_in,sig_out},我只需要sig_in,field_name,field_type,field_dim信息,以及嵌套记录的方式相同。我将查看所有推荐的选项,并尝试修改它们以满足需求。

感谢您的帮助!   - 乔

3 个答案:

答案 0 :(得分:0)

此XSLT能够生成您发布的结果:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" encoding="UTF-8" />
  <xsl:template match="/" name="service_signature">
    <sig_in>
      <xsl:for-each select="/record[@name='sig_in']/array[@name]/record">
        <record>
          <field_name><xsl:value-of select="value[@name='field_name']/text()"/></field_name>
          <field_type><xsl:value-of select="value[@name='field_type']/text()"/></field_type>
          <field_dim><xsl:value-of select="value[@name='field_dim']/text()"/></field_dim>
        </record>
      </xsl:for-each>
    </sig_in>
  </xsl:template>

</xsl:stylesheet>

但是,如果你想迭代每个记录的使用:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" encoding="UTF-8" />
  <xsl:template match="/" name="service_signature">
    <sig_in>
      <xsl:for-each select="//array[@name]/record">
        <record>
          <field_name><xsl:value-of select="value[@name='field_name']/text()"/></field_name>
          <field_type><xsl:value-of select="value[@name='field_type']/text()"/></field_type>
          <field_dim><xsl:value-of select="value[@name='field_dim']/text()"/></field_dim>
        </record>
      </xsl:for-each>
    </sig_in>
  </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

这是一个可以帮助你的xslt。

<?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 indent="yes"/>
    <xsl:template match="*">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="record|value">
        <xsl:choose>
            <xsl:when test="@name">
                <xsl:element name="{@name}">
                    <xsl:apply-templates/>
                </xsl:element>              
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates/>
                </xsl:copy>             
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

使用您的XML:

<record name="sig_in">
    <array depth="1" name="rec_fields" type="record">
        <record>
            <value name="field_name">docTest</value>
            <value name="field_type">record</value>
            <value name="field_dim">0</value>
            <array depth="1" name="rec_fields" type="record">
                <record javaclass="com.wm.util.Values">
                    <value name="field_name">doc.name</value>
                    <value name="field_type">string</value>
                    <value name="field_dim">0</value>
                </record>
            </array>
        </record>
        <record>
            <value name="field_name">docListTest</value>
            <value name="field_type">record</value>
            <value name="field_dim">1</value>
            <array depth="1" name="rec_fields" type="record">
                <record>
                    <value name="field_name">d0</value>
                    <value name="field_type">record</value>
                    <value name="field_dim">0</value>
                    <array depth="1" name="rec_fields" type="record">
                        <record>
                            <value name="field_name">d0.name</value>
                            <value name="field_type">string</value>
                            <value name="field_dim">0</value>
                        </record>
                    </array>
                </record>
            </array>
        </record>
        <record>
            <value name="field_name">packages_should_work</value>
            <value name="field_type">recref</value>
            <value name="field_dim">0</value>
            <value name="rec_ref">data:packages</value>
        </record>
        <record>
            <value name="field_name">packages_list_should_work</value>
            <value name="field_type">recref</value>
            <value name="field_dim">1</value>
            <value name="rec_ref">data:packages</value>
        </record>
    </array>
</record>

结果是:

<?xml version="1.0" encoding="utf-8"?>
<sig_in>
   <record>
      <field_name>docTest</field_name>
      <field_type>record</field_type>
      <field_dim>0</field_dim>
      <record>
         <field_name>doc.name</field_name>
         <field_type>string</field_type>
         <field_dim>0</field_dim>
      </record>
   </record>
   <record>
      <field_name>docListTest</field_name>
      <field_type>record</field_type>
      <field_dim>1</field_dim>
      <record>
         <field_name>d0</field_name>
         <field_type>record</field_type>
         <field_dim>0</field_dim>
         <record>
            <field_name>d0.name</field_name>
            <field_type>string</field_type>
            <field_dim>0</field_dim>
         </record>
      </record>
   </record>
   <record>
      <field_name>packages_should_work</field_name>
      <field_type>recref</field_type>
      <field_dim>0</field_dim>
      <rec_ref>data:packages</rec_ref>
   </record>
   <record>
      <field_name>packages_list_should_work</field_name>
      <field_type>recref</field_type>
      <field_dim>1</field_dim>
      <rec_ref>data:packages</rec_ref>
   </record>
</sig_in>

答案 2 :(得分:0)

尝试这样的事情:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <xsl:template match="value[@name]">
        <xsl:element name="{@name}">
            <xsl:value-of select="text()"/>
        </xsl:element>

    </xsl:template>

    <xsl:template match="record">
            <xsl:copy>
                <xsl:apply-templates  />
            </xsl:copy>
    </xsl:template>
     <xsl:template match="/*">
        <xsl:apply-templates  />
    </xsl:template>

    <xsl:template match="node()">
        <xsl:apply-templates select="node()" />
    </xsl:template>
</xsl:stylesheet>

将生成以下输出:

<?xml version="1.0"?>
<record>
  <field_name>docTest</field_name>
  <field_type>record</field_type>
  <field_dim>0</field_dim>
  <record>
    <field_name>doc.name</field_name>
    <field_type>string</field_type>
    <field_dim>0</field_dim>
  </record>
</record><record>
  <field_name>docListTest</field_name>
  <field_type>record</field_type>
  <field_dim>1</field_dim>
  <record>
    <field_name>d0</field_name>
    <field_type>record</field_type>
    <field_dim>0</field_dim>
    <record>
      <field_name>d0.name</field_name>
      <field_type>string</field_type>
      <field_dim>0</field_dim>
    </record>
  </record>
</record><record>
  <field_name>packages_should_work</field_name>
  <field_type>recref</field_type>
  <field_dim>0</field_dim>
  <rec_ref>data:packages</rec_ref>
</record><record>
  <field_name>packages_list_should_work</field_name>
  <field_type>recref</field_type>
  <field_dim>1</field_dim>
  <rec_ref>data:packages</rec_ref>
</record>

将doe更新为更多相关信息:

您可以轻松地在记录或值模板中添加某些条件。 这就是我所理解的:只考虑具有@name值记录的记录是&#34; sig_in&#34;。
试试这个:

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

    <xsl:template match="value[@name = 'field_name' or
                            @name = 'field_type' or
                            @name = 'field_dim']">
        <xsl:element name="{@name}">
            <xsl:value-of select="text()"/>
        </xsl:element>

    </xsl:template>

    <xsl:template match="record[descendant-or-self::record[@name='sig_in'] or 
                  ancestor::record[@name='sig_in']]">
            <xsl:copy>
                <xsl:apply-templates  />
            </xsl:copy>
    </xsl:template>


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

    <xsl:template match="node()">
        <xsl:apply-templates select="node()" />
    </xsl:template>
</xsl:stylesheet>