【问题标题】:Recursive XSLT transformation递归 XSLT 转换
【发布时间】:2013-05-07 07:18:29
【问题描述】:

又是一个有问题的任务。我有一个不太好的 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 中也需要相同的类型。或者在公寓里,我需要在父节点和子节点中有一些唯一标识符,这样我就知道哪个包含哪个。无论如何,我都不应该松动结构。

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

感谢您的每一个帮助! - 乔

【问题讨论】:

  • 只是为了清楚这一点。输出应该包含来自输​​入的任何记录而不考虑任何条件?
  • 结构应该保持不变。如果一条记录嵌套在另一个记录中,它也应该嵌套在生成的 xml 中。

标签: xml xslt


【解决方案1】:

试试这样的:

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

更新能源部以获取更多相关信息:

您可以轻松地将某些条件放入记录或值模板中。 这就是我的理解:只考虑具有@name 值的记录是“sig_in”。
试试这个:

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

【讨论】:

  • 看起来很有希望,但它适合每个记录或值节点,但我只需要特定的。这确实是我的错误,我只是试图节省大量空间而不粘贴整个大 xml。我将更新我原来的 xml 示例。
  • @Joey:你看更新了吗?这仅考虑将@name='sig_in@name='sig_in作为父级或子级(任何深度)的记录。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这是一个可以帮助你的 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>
    

    【讨论】:

      猜你喜欢
      • 2013-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-23
      • 1970-01-01
      相关资源
      最近更新 更多