Xml 递归XSLT转换

Xml 递归XSLT转换,xml,xslt,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> <!--

这又是一项有问题的任务。我有一个不太好的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>

博士
记录
0
文件名
一串
0
文档列表测试
记录
1.
d0
记录
0
d0.名称
一串
0
包应该有用
重新引用
0
数据:包
包装清单应该有效
重新引用
1.
数据:包
为了简单起见,我需要将这个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>

博士
记录
0
文档列表测试
记录
1.
包应该有用
重新引用
0
包装清单应该有效
重新引用
1.
到目前为止,我创建了如下内容:

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

虽然它对主元素有效,但对嵌套记录无效。我可以为每个项创建一个xsl:for,如果类型是record,则迭代每个项,但这解决不了多少问题;因为它可以是任何深度。我知道我应该使用递归,我只是想象不出在这种特殊情况下我该怎么做

@编辑-对嵌套类型进行一些更正:

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

目录树
记录
1.
d0
记录
0
d0.名称
一串
0
因此,正如您可以看到原始类型嵌套在何处一样,我也需要在生成的xml中使用相同的类型。或者在平面中,我需要在父节点和子节点中使用一些唯一标识符,以便知道哪个节点包含哪个节点。无论如何,我都不应该使结构松动

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

谢谢你的帮助!
-Joe

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

以下是一个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>

博士
记录
0
文件名
一串
0
文档列表测试
记录
1.
d0
记录
0
d0.名称
一串
0
包应该有用
重新引用
0
数据:包
包装清单应该有效
重新引用
1.
数据:包
结果是:

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

博士
记录
0
文件名
一串
0
文档列表测试
记录
1.
d0
记录
0
d0.名称
一串
0
包应该有用
重新引用
0
数据:包
包装清单应该有效
重新引用
1.
数据:包

尝试以下方法:

<?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: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中。看起来很有希望,但它适合于每个记录或值节点,但我只需要特定的记录或值节点。这确实是我的又一个错误,我只是试图节省大量空间,而不是粘贴整个大型xml。我将更新我原来的xml示例。@Joey:你看过更新了吗。这只考虑带有
@name='sig的记录_in@name='sig_in
作为父项或子项(任何深度)。