[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Hierarchy based on indentation (long)


Subject: Re: [xsl] Hierarchy based on indentation (long)
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Sun, 8 Dec 2002 14:49:16 -0800 (PST)

"Grainne Reilly" <greilly1@xxxxxxxxx> wrote in message
news:5.1.0.14.0.20021208153308.00b38b08@xxxxxxxxxxxxxxxxx
> Hi,
> Another long question from me.
> I have a source xml similar to that shown below - where there is an
> implicit hierarchy based on the indentation of the content of each
cell.
I
> want to transform it to the result xml also shown below.  I have
written a
> stylesheet which seems to achieve this, but being a novice at xslt I
am
> sure that there are much better ways to achieve this result.  I would
> really appreciate any suggestions to improve on this.
> Thanks,
> Grainne.
>
> ==========
> source xml
> ==========
> <?xml version="1.0" encoding="UTF-8"?>
> <table>
>  <row><cell>Level one description(1)</cell></row>
>  <row><cell>   Level two description(2)</cell></row>
>  <row><cell>      Level three description(3)</cell></row>
>  <row><cell>   Level two description(4)</cell></row>
>  <row><cell>      Level three description(5)</cell></row>
>  <row><cell>Level one description(6)</cell></row>
>  <row><cell>   Level two description(7)</cell></row>
>  <row><cell>      Level three description(8)</cell></row>
>  <row><cell>       Level four description(9)</cell></row>
>  <row><cell>   Level two description(10)</cell></row>
> </table>
>
> ==========
> result xml
> ==========
> <?xml version="1.0" encoding="UTF-8"?>
> <descriptions>
>     <description row="1" level="1">Level one
description(1)</description>
> </descriptions>
> <descriptions>
>     <description row="2" level="1">Level one
description(1)</description>
>     <description row="2" level="2">   Level two
description(2)</description>
> </descriptions>
> <descriptions>
>     <description row="3" level="1">Level one
description(1)</description>
>     <description row="3" level="2">   Level two
description(2)</description>
>     <description row="3" level="3">      Level three
> description(3)</description>
> </descriptions>
> <descriptions>
>     <description row="4" level="1">Level one
description(1)</description>
>     <description row="4" level="2">   Level two
description(4)</description>
> </descriptions>
> <descriptions>
>     <description row="5" level="1">Level one
description(1)</description>
>     <description row="5" level="3">   Level two
description(4)</description>
>     <description row="5" level="4">      Level three
> description(5)</description>
> </descriptions>
> <descriptions>
>     <description row="6" level="1">Level one
description(6)</description>
> </descriptions>
> <descriptions>
>     <description row="7" level="1">Level one
description(6)</description>
>     <description row="7" level="2">   Level two
description(7)</description>
> </descriptions>
> <descriptions>
>     <description row="8" level="1">Level one
description(6)</description>
>     <description row="8" level="2">   Level two
description(7)</description>
>     <description row="8" level="3">      Level three
> description(8)</description>
> </descriptions>
> <descriptions>
>     <description row="9" level="1">Level one
description(6)</description>
>     <description row="9" level="2">   Level two
description(7)</description>
>     <description row="9" level="3">      Level three
> description(8)</description>
>     <description row="9" level="4">       Level four
> description(9)</description>
> </descriptions>
> <descriptions>
>     <description row="10" level="1">Level one
description(6)</description>
>     <description row="10" level="2">   Level two
description(10)</description>
> </descriptions>
>
> =============
> xslt stylesheet
> =============
> <?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" version="1.0" encoding="UTF-8"
indent="yes"/>
>
>  <xsl:template match="/">
>   <xsl:apply-templates select="/table/row" mode="descriptions"/>
>  </xsl:template>
>
>  <xsl:template match="table/row" mode="descriptions">
>   <xsl:variable name="indent"
>
select="string-length(substring-before(cell,substring(normalize-space(cell),
1,1)))"/>
>   <xsl:variable name="row" select="position()"/>
>   <descriptions>
>   <xsl:choose>
>    <xsl:when test="$indent = 0">
>     <description row="{$row}">
>      <xsl:attribute name="level">
>       <xsl:value-of select="1"/>
>      </xsl:attribute>
>      <xsl:value-of select="cell"/>
>     </description>
>    </xsl:when>
>    <xsl:otherwise>
>     <xsl:apply-templates
>
select="preceding::cell[(string-length(substring-before(.,substring(normaliz
e-space(.),1,1))))
> = 0][1]" mode="descHierarchy">
>      <xsl:with-param name="endAnchor" select="generate-id(cell)"/>
>      <xsl:with-param name="indent" select="$indent"/>
>      <xsl:with-param name="row" select="$row"/>
>     </xsl:apply-templates>
>    </xsl:otherwise>
>   </xsl:choose>
>   </descriptions>
>  </xsl:template>
>
>  <xsl:template match="cell" mode="descHierarchy">
>   <xsl:param name="endAnchor"/>
>   <xsl:param name="indent" select="0"/>
>   <xsl:param name="row" select="1"/>
>   <xsl:for-each select=".|following::cell[generate-id() =
> $endAnchor]|following::cell[following::cell[generate-id() =
$endAnchor]][
>
(string-length(substring-before(.,substring(normalize-space(.),1,1))))
&lt;
> $indent]" >
>    <xsl:variable name="thisIndent"
>
select="(string-length(substring-before(.,substring(normalize-space(.),1,1))
))"/>
>    <xsl:choose>
>     <xsl:when test="not(following::cell[
following::cell[generate-id() =
> $endAnchor] ][
>
(string-length(substring-before(.,substring(normalize-space(.),1,1))))
=
> $thisIndent ])">
>      <description row="{$row}">
>       <xsl:attribute name="level">
>        <xsl:value-of select="position()"/>
>       </xsl:attribute>
>       <xsl:value-of select="."/>
>      </description>
>     </xsl:when>
>    </xsl:choose>
>   </xsl:for-each>
>  </xsl:template>
>
> </xsl:stylesheet>



Hi Grainne,

It seems to me that the following solution is simpler. It uses a
recursively called named template to generate the descriptions, and
also the fact that the indent for every next level is 3:


<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:template match="/">
    <xsl:for-each select="/*/row">
      <descriptions>
      <xsl:call-template name="genDescription">
        <xsl:with-param name="pNode" select="."/>
        <xsl:with-param name="pRow" select="position()"/>
        <xsl:with-param name="pLevel"

select="string-length(substring-before(cell,
                                       substring(normalize-space(cell),
                                                 1,1
                                                 )
                                       )
                     )
                      div 3 + 1"/>
      </xsl:call-template>
      </descriptions>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="genDescription">
    <xsl:param name="pNode" select="/.."/>
    <xsl:param name="pRow" />
    <xsl:param name="pLevel"/>


  <xsl:if test="$pLevel > 1">
    <xsl:variable name="vindentParent" select="($pLevel - 2) * 3"/>

    <xsl:variable name="vParent"
     select="preceding-sibling::row
               [not(translate(substring(cell, 1, $vindentParent),
                              ' ', ''
                              )
                    )
                and substring(cell, $vindentParent + 1, 1) != ' '
               ]
                [1]"/>

    <xsl:call-template name="genDescription">
      <xsl:with-param name="pNode" select="$vParent"/>
      <xsl:with-param name="pRow" select="$pRow"/>
      <xsl:with-param name="pLevel" select="$pLevel - 1"/>
    </xsl:call-template>
  </xsl:if>

  <description row="{$pRow}" level="{$pLevel}">
    <xsl:value-of select="$pNode/cell"/>
  </description>

  </xsl:template>
</xsl:stylesheet>

When applied on your source xml document, the following correct result
is produced:

<descriptions>
   <description row="1" level="1">Level one
description(1)</description>
</descriptions>
<descriptions>
   <description row="2" level="1">Level one
description(1)</description>
   <description row="2" level="2">   Level two
description(2)</description>
</descriptions>
<descriptions>
   <description row="3" level="1">Level one
description(1)</description>
   <description row="3" level="2">   Level two
description(2)</description>
   <description row="3" level="3">      Level three
description(3)</description>
</descriptions>
<descriptions>
   <description row="4" level="1">Level one
description(1)</description>
   <description row="4" level="2">   Level two
description(4)</description>
</descriptions>
<descriptions>
   <description row="5" level="1">Level one
description(1)</description>
   <description row="5" level="2">   Level two
description(4)</description>
   <description row="5" level="3">      Level three
description(5)</description>
</descriptions>
<descriptions>
   <description row="6" level="1">Level one
description(6)</description>
</descriptions>
<descriptions>
   <description row="7" level="1">Level one
description(6)</description>
   <description row="7" level="2">   Level two
description(7)</description>
</descriptions>
<descriptions>
   <description row="8" level="1">Level one
description(6)</description>
   <description row="8" level="2">   Level two
description(7)</description>
   <description row="8" level="3">      Level three
description(8)</description>
</descriptions>
<descriptions>
   <description row="9" level="1">Level one
description(6)</description>
   <description row="9" level="2">   Level two
description(7)</description>
   <description row="9" level="3">      Level three
description(8)</description>
   <description row="9" level="4">         Level four
description(9)</description>
</descriptions>
<descriptions>
   <description row="10" level="1">Level one
description(6)</description>
   <description row="10" level="2">   Level two
description(10)</description>
</descriptions>




=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL

__________________________________________________
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now.
http://mailplus.yahoo.com

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread
Keywords