xsl-list
[Top] [All Lists]

Hierarchy based on indentation (long)

2002-12-08 13:49:08
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(normalize-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>



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



<Prev in Thread] Current Thread [Next in Thread>