扁平结构,使用XSLT 1.0可以嵌套/分层

时间:2019-02-03 20:20:38

标签: xml xslt xslt-1.0

是的,我知道一些答案,例如Flat to Nested structure based on attribute value using XSLT,但对我来说有重要的区别。

给出以下扁平XML结构。级别信息可能包含空白。包含级别信息的元素之间可以有任意数量的元素没有级别信息。应该使用级别规范将这些元素分配给上一个元素

<doc>
  <item>
    <meta>
        <text>abc</text>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>1</level>
        <title>a</title>
      </para>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>2</level>
        <title>b</title>
      </para>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>1</level>
        <title>c</title>
      </para>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>2</level>
        <title>d</title>
      </para>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>2</level>
        <title>e</title>
      </para>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>4</level>
        <title>f</title>
      </para>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>1</level>
        <title>g</title>
      </para>
    </meta>
  </item>
  <item>
    <meta>
        <text>def</text>
    </meta>
  </item>
  <item>
    <meta>
        <text>ghi</text>
    </meta>
  </item>
  <item>
    <meta>
      <para>
        <level>2</level>
        <title>h</title>
      </para>
    </meta>
  </item>
</doc>

转换后的结果应如下所示……

<text>abc</text>
<test title="a">
   <test title="b"/>
</test>
<test para="c">
   <test title="d"/>
   <test title="e">
      <test para="f"/>
   </test>
</test>
<test title="g">
    <text>def</text>
    <text>ghi</text>
   <test title="h"/>
</test>

我的转换方法如下。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="child" match="item"
    use="generate-id(preceding-sibling::item[(meta/para/level) &lt;= ((current()/meta/para/level) - 1)][1])"/>

    <xsl:template match="/doc">
        <xsl:apply-templates select="item[(meta/para/level) = 1]"/>
    </xsl:template>

    <xsl:template match="item">
        <test title="{meta/para/title}">
            <xsl:apply-templates select="key('child', generate-id())"/>
        </test>
    </xsl:template>

</xsl:stylesheet>

很遗憾,我找不到解决方法。

1 个答案:

答案 0 :(得分:1)

怎么样:

XSLT 1.0

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

<xsl:key name="child1" 
         match="item[meta/para/level]"
         use="generate-id(preceding-sibling::item[meta/para/level &lt; current()/meta/para/level][1])"/>

<xsl:key name="child2" 
         match="item[meta/text]"
         use="generate-id(preceding-sibling::item[meta/para/level][1])"/>

<xsl:template match="/doc">
    <root>
        <xsl:apply-templates select="item[meta/para/level = 1] | key('child2', '')"/>
    </root>
</xsl:template>

<xsl:template match="item[meta/para/title]">
    <test title="{meta/para/title}">
        <xsl:apply-templates select="key('child1', generate-id()) | key('child2', generate-id())"/>
    </test>
</xsl:template>

<xsl:template match="item[meta/text]">
    <text>
        <xsl:value-of select="meta/text"/>
    </text>
</xsl:template>

</xsl:stylesheet>

我添加了root元素以使结果成为格式正确的XML。