XSLT: turn flat list into hierarchy

。_饼干妹妹 提交于 2019-12-22 17:58:17

问题


I try to understand the grouping functions in XSLT 2.0. My source document is

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

and the result should be something like

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

That is: if there is a following entry with a deeper level (b is deeper than a,...) the next section should be child of the current, if it is the same level, it should be the next sibling.

I've tried with xsl:group-by select="entry" group-by="@level" which gives me a sensible grouping, but I don't know how to open the section to go down, if there is a down.

There is another similar question which states that "In XSLT 2.0 it would be rather easy with the new grouping functions." - it might be easy but I don't get it.


回答1:


Here is an example:

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

Should work with any levels from 'a' to 'z'.

Saxon 9.4, when running above against

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

outputs

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


来源:https://stackoverflow.com/questions/9175991/xslt-turn-flat-list-into-hierarchy

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!