XSLT从扁平结构转换为嵌套

时间:2013-02-09 20:48:33

标签: xslt

我无法使用简单的(?)XSLT转换进行管理。

有一个输入平面结构的XML:

<root>
    <attribute_a>abc</attribute_a>
    <attribute_b>def</attribute_b>
    <attribute_c>ghi</attribute_c>
    <attribute_a>123</attribute_a>
    <attribute_b>456</attribute_b>
    <attribute_c>789</attribute_c>
    <attribute_a>xxx</attribute_a>
    <attribute_b>xxx</attribute_b>
    <attribute_c>xxx</attribute_c>
</root>

我应该把它转换成这样的XML:

<root>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>123</attribute_a>
        <attribute_b>456</attribute_b>
        <attribute_c>789</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>xxx</attribute_a>
        <attribute_b>xxx</attribute_b>
        <attribute_c>xxx</attribute_c>
    </attribute>
</root>

但问题是转型后的问题:

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

    <xsl:template match="/">
        <root>
            <xsl:for-each select="root/attribute_a">
                <attribute>
                    <attribute_a>
                        <xsl:value-of select="../attribute_a" />
                    </attribute_a>
                    <attribute_b>
                        <xsl:value-of select="../attribute_b" />
                    </attribute_b>
                    <attribute_c>
                        <xsl:value-of select="../attribute_c" />
                    </attribute_c>
                </attribute>
            </xsl:for-each>
        </root>
        <xsl:apply-templates />
    </xsl:template>
</xsl:stylesheet>

我有这样的事情:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
</root>

我对XSLT不是很有经验 - 你有什么想法吗? :(

的问候, A. M。

1 个答案:

答案 0 :(得分:2)

这应该可以解决问题:

<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="/">
    <root>
      <xsl:for-each select="root/attribute_a">
        <xsl:variable name="pos" select="position()"/>
        <attribute>
          <xsl:apply-templates
            select="../attribute_a[$pos] | 
                    ../attribute_b[$pos] |
                    ../attribute_c[$pos]" />
        </attribute>
      </xsl:for-each>
    </root>
  </xsl:template>
</xsl:stylesheet>

我建议更进一步,使用单独的模板而不是for-each

<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="/">
    <root>
      <xsl:apply-templates select="root/attribute_a" mode="group" />
    </root>
  </xsl:template>

  <xsl:template match="attribute_a" mode="group">
    <xsl:variable name="pos" select="position()"/>
    <attribute>
      <xsl:apply-templates
        select="../attribute_a[$pos] | ../attribute_b[$pos] | ../attribute_c[$pos]" />
    </attribute>
  </xsl:template>
</xsl:stylesheet>

当您的样本输入上运行这些XSLT中的任何一个时,它会产生以下输出:

<root>
  <attribute>
    <attribute_a>abc</attribute_a>
    <attribute_b>def</attribute_b>
    <attribute_c>ghi</attribute_c>
  </attribute>
  <attribute>
    <attribute_a>123</attribute_a>
    <attribute_b>456</attribute_b>
    <attribute_c>789</attribute_c>
  </attribute>
  <attribute>
    <attribute_a>xxx</attribute_a>
    <attribute_b>xxx</attribute_b>
    <attribute_c>xxx</attribute_c>
  </attribute>
</root>