Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
331 views
in Technique[技术] by (71.8m points)

XSLT How to apply recursion to transform from a flat file to a nested tree

I know that there are several other question/answers similar to this, but I haven't read one that addresses my confusion over this transform. I need to move an XML document from this format:

<root>
    <row>
        <t0>1</t0>
        <title>Main Title</title>
    </row>
    <row>
        <t0>2</t0>
        <title>Secondary Title</title>
        <note>Note</note>
    </row>
    <row>
        <t0>3</t0>
        <title>Tertiary Title</title>
    </row>
    <row>
        <t0>3</t0>
        <title>Another Title</title>
    </row>
    <row>
        <t0>2</t0>
        <title>A Second Secondary Title</title>
        <note>Note</note>
    </row>
    <row>  
        <t0>3</t0>
        <title>Third Level Title</title>
    </row>
    <row> 
        <t0>3</t0>
        <title>Title at Level Three</title>
    </row>
</root>

to this format:

<root>
    <header>List</header>
    <t01>
        <title>Main Title</title>
        <t02>
            <title>Secondary Title</title>
            <note>Note</note>
            <t03>
                <title>Tertiary Title</title>
            </t03>
            <t03>
                <title>Another Title</title>
            </t03>
        </t02>
        <t02>
            <title>A Second Secondary Title</title>
            <note>Note</note>
            <t03>
                <title>Third Level Title</title>
            </t03>
            <t03>   
                <title>Title at Level Three</title>
            </t03>
        </t02>
    </t01>
</root>

I'm using XSLT 2.0 and I'm getting hung up on applying for-each-group recursively. Thanks for your time & trouble.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

With XSLT 2.0 I would strongly suggest to use the for-each-grouping together with a recursive function or template; below is a sample using a function:

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

<xsl:output indent="yes"/>

<xsl:function name="mf:group" as="element()*">
  <xsl:param name="elements" as="element(row)*"/>
  <xsl:param name="level" as="xs:integer"/>
  <xsl:for-each-group select="$elements" group-starting-with="row[t0 = $level]">
    <xsl:element name="t{format-number($level, '00')}">
      <xsl:copy-of select="* except t0"/>
      <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
    </xsl:element>
  </xsl:for-each-group>
</xsl:function>

<xsl:template match="root">
  <xsl:copy>
    <header>List</header>
    <xsl:sequence select="mf:group(row, 1)"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...