XSLT:将平面列表转换为层次结构

时间:2012-02-07 12:08:19

标签: xslt xslt-2.0

我尝试理解XSLT 2.0中的分组功能。我的源文件是

<root>
  <entry level="a" name="aaa"/>
  <entry level="a" name="bbb"/>
  <entry level="b" name="ccc"/>
  <entry level="c" name="ddd"/>
  <entry level="a" name="eee"/>
  <entry level="a" name="fff"/>
  <entry level="b" name="ggg"/>
</root>

,结果应该是

<section name="aaa"/>
<section name="bbb">
  <section name="ccc">
    <section name="ddd" />
  </section>
</section>
<section name="eee"/>
<section name="fff">
  <section name="ggg" />
</section>

那就是:如果有一个更深层次的后续条目(b比a更深,......),下一节应该是当前的子节点,如果它是同一级别,它应该是下一个兄弟节点

我尝试使用xsl:group-by select="entry" group-by="@level"给了我一个明智的分组,但我不知道如果有一个失败,如何打开该部分。

another similar question表明“在XSLT 2.0中,使用新的分组功能会相当容易。” - 这可能很容易,但我不明白。

1 个答案:

答案 0 :(得分:3)

以下是一个例子:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs mf"
  version="2.0">

  <xsl:output indent="yes"/>

  <xsl:function name="mf:group" as="element(section)*">
    <xsl:param name="entries" as="element(entry)*"/>
    <xsl:param name="level" as="xs:string"/>
    <xsl:for-each-group select="$entries" group-starting-with="entry[@level = $level]">
      <section name="{@name}">
        <xsl:sequence select="mf:group(current-group() except ., codepoints-to-string(string-to-codepoints($level)[1] + 1))"/>
      </section>
    </xsl:for-each-group>
  </xsl:function>

  <xsl:template match="root">
    <xsl:copy>
      <xsl:sequence select="mf:group(entry, 'a')"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

应该使用从'a'到'z'的任何级别。

撒克逊人9.4,在上面跑时

<root>
  <entry level="a" name="aaa"/>
  <entry level="a" name="bbb"/>
  <entry level="b" name="ccc"/>
  <entry level="c" name="ddd"/>
  <entry level="a" name="eee"/>
  <entry level="a" name="fff"/>
  <entry level="b" name="ggg"/>
</root>

输出

<root>
   <section name="aaa"/>
   <section name="bbb">
      <section name="ccc">
         <section name="ddd"/>
      </section>
   </section>
   <section name="eee"/>
   <section name="fff">
      <section name="ggg"/>
   </section>
</root>