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)))) < > $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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Hierarchy based on indentatio, Grainne Reilly | Thread | Re: [xsl] Hierarchy based on inden, Grainne Reilly |
[xsl] Hierarchy based on indentatio, Grainne Reilly | Date | [xsl] Dynamically Creating XSL docu, Kevin Friend |
Month |