looping templates

Discussion in 'XML' started by Ruthless, Dec 29, 2003.

  1. Ruthless

    Ruthless Guest

    Hello.

    I've got a simple XML:

    <?xml version="1.0" encoding="iso-8859-2"?>
    <?xml-stylesheet type="text/xsl" href="4.xsl"?>

    <struct>

    <node level="1" no="1">

    <node level="2" no="2" />
    <node level="2" no="3" />
    <node level="2" no="4" />
    </node>

    <node level="1" no="5">

    <node level="2" no="6" />
    <node level="2" no="7" />
    <node level="2" no="8" />
    </node>

    </struct>

    and i want to display all the levels starting from 1 to 2

    I've got my xslt sth like this:

    <?xml version="1.0" encoding="ISO-8859-2" ?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:eek:utput method="html"/>

    <xsl:template match="/">

    <html>
    <body>

    <table align="center" border="1">
    <tr>
    <th>Name</th><th>No.</th><th>Level</th>
    </tr>

    <xsl:for-each select="//node">
    <xsl:sort select="@level"/>

    <xsl:if test="@level='1'">
    <tr>
    <td align="center"><xsl:value-of select="name()"/></td>
    <td><xsl:value-of select="@no"/></td>
    <td><xsl:value-of select="@level"/></td>
    </tr>
    </xsl:if>
    </xsl:for-each>

    </table>

    <!-- now goes level 2-->

    <table align="center" border="1">
    <tr>
    <th>Name</th><th>No.</th><th>Level</th>
    </tr>

    <xsl:for-each select="//node">
    <xsl:sort select="@level"/>

    <xsl:if test="@level='2'">
    <tr>
    <td align="center"><xsl:value-of select="name()"/></td>
    <td><xsl:value-of select="@no"/></td>
    <td><xsl:value-of select="@level"/></td>
    </tr>
    </xsl:if>
    </xsl:for-each>

    </table>
    </body>
    </html>

    </xsl:template>

    </xsl:stylesheet>

    It works fine but it's useless when there would be more then 2 levels - how
    can i loop this template to go through all the levels - each level has a new
    table(just like above)

    and second thing how can i count node with e.g. attributes level="2"?

    I've tried sth like this:
    <xsl:template match="/">
    <xsl:variable name="ile" select="count(//node@level='2')" />
    </xsl:template>

    and then:

    <b><xsl:value-of select="$ile"/></b>

    but it's wrong and i've got warning msg.

    thanks in advance
    greetings R


    ---
    Outgoing mail is certified Virus Free.
    Checked by AVG anti-virus system (http://www.grisoft.com).
    Version: 6.0.554 / Virus Database: 346 - Release Date: 03-12-20
    Ruthless, Dec 29, 2003
    #1
    1. Advertising

  2. The way to do this is the following:

    This transformation:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
    <html>
    <body>
    <xsl:apply-templates/>
    </body>
    </html>
    </xsl:template>

    <xsl:template match="*[node]">
    <table align="center" border="1">
    <tr>
    <th>Name</th><th>No.</th><th>Level</th>
    <xsl:apply-templates select="node" mode="display"/>
    </tr>
    </table>
    <br />
    <br />
    <xsl:apply-templates select="node"/>
    </xsl:template>

    <xsl:template match="node" mode="display">
    <tr>
    <td align="center"><xsl:value-of select="name()"/></td>
    <td><xsl:value-of select="@no"/></td>
    <td><xsl:value-of select="@level"/></td>
    </tr>
    </xsl:template>
    </xsl:stylesheet>

    When applied on this source.xml:

    <struct>
    <node level="1" no="1">
    <node level="2" no="2" />
    <node level="2" no="3">
    <node level="3" no="4"/>
    </node>
    <node level="2" no="5" />
    </node>
    <node level="1" no="6">
    <node level="2" no="7">
    <node level="3" no="8"/>
    <node level="3" no="9"/>
    </node>
    <node level="2" no="10" />
    <node level="2" no="11" />
    </node>
    </struct>

    Produces this output (as displayed in the browser):

    Name No. Level

    node 1 1

    node 6 1




    Name No. Level

    node 2 2

    node 3 2

    node 5 2




    Name No. Level

    node 4 3




    Name No. Level

    node 7 2

    node 10 2

    node 11 2




    Name No. Level

    node 8 3

    node 9 3


    However you want all nodes belonging to the same level to be displayed in a
    single table.

    In this case this transformation:


    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:key name="kByLevel" match="node" use="@level"/>

    <xsl:variable name="vMinMaxLevel">
    <xsl:for-each
    select="//node[generate-id()
    =
    generate-id(key('kByLevel', @level)[1])
    ]">
    <xsl:sort select="@level" data-type="number"/>

    <xsl:if test="position() = 1 or position() = last()">
    <xsl:value-of select="@level"/>
    <xsl:if test="position() = 1">|</xsl:if>
    </xsl:if>
    </xsl:for-each>
    </xsl:variable>

    <xsl:template match="/">
    <xsl:call-template name="displayH">
    <xsl:with-param name="pLevel"
    select="substring-before($vMinMaxLevel, '|')"/>
    <xsl:with-param name="pMaxLevel"
    select="substring-after($vMinMaxLevel, '|')"/>

    </xsl:call-template>
    </xsl:template>

    <xsl:template name="displayH">
    <xsl:param name="pLevel" select="1"/>
    <xsl:param name="pMaxLevel" select="1"/>

    <xsl:variable name="vThisLevel"
    select="key('kByLevel', $pLevel)"/>

    <xsl:if test="$pLevel &lt;= $pMaxLevel
    and $vThisLevel">
    <table align="center" border="1">
    <tr>
    <th>Name</th><th>No.</th><th>Level</th>
    <xsl:apply-templates select="$vThisLevel"/>
    </tr>
    </table>
    <br />
    <br />
    <xsl:call-template name="displayH">
    <xsl:with-param name="pLevel" select="$pLevel + 1"/>
    <xsl:with-param name="pMaxLevel" select="$pMaxLevel"/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>

    <xsl:template match="node">
    <tr>
    <td align="center"><xsl:value-of select="name()"/></td>
    <td><xsl:value-of select="@no"/></td>
    <td><xsl:value-of select="@level"/></td>
    </tr>
    </xsl:template>
    </xsl:stylesheet>


    when applied on the same source.xml produces the wanted output:

    Name No. Level

    node 1 1

    node 6 1


    Name No. Level

    node 2 2

    node 3 2

    node 5 2

    node 7 2

    node 10 2

    node 11 2


    Name No. Level

    node 4 3

    node 8 3

    node 9 3


    This transformation works even in cases when levels are not consecutive
    numbers (or even positive numbers) and when we do not know the starting
    level.

    Hope this helped.

    Dimitre Novatchev.
    FXSL developer, XML Insider,

    http://fxsl.sourceforge.net/ -- the home of FXSL
    Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html


    "Ruthless" <ruthless@NO_SPAM.poczta.onet.pl> wrote in message
    news:bsq92m$3p5$...
    > Hello.
    >
    > I've got a simple XML:
    >
    > <?xml version="1.0" encoding="iso-8859-2"?>
    > <?xml-stylesheet type="text/xsl" href="4.xsl"?>
    >
    > <struct>
    >
    > <node level="1" no="1">
    >
    > <node level="2" no="2" />
    > <node level="2" no="3" />
    > <node level="2" no="4" />
    > </node>
    >
    > <node level="1" no="5">
    >
    > <node level="2" no="6" />
    > <node level="2" no="7" />
    > <node level="2" no="8" />
    > </node>
    >
    > </struct>
    >
    > and i want to display all the levels starting from 1 to 2
    >
    > I've got my xslt sth like this:
    >
    > <?xml version="1.0" encoding="ISO-8859-2" ?>
    > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    > version="1.0">
    >
    > <xsl:eek:utput method="html"/>
    >
    > <xsl:template match="/">
    >
    > <html>
    > <body>
    >
    > <table align="center" border="1">
    > <tr>
    > <th>Name</th><th>No.</th><th>Level</th>
    > </tr>
    >
    > <xsl:for-each select="//node">
    > <xsl:sort select="@level"/>
    >
    > <xsl:if test="@level='1'">
    > <tr>
    > <td align="center"><xsl:value-of select="name()"/></td>
    > <td><xsl:value-of select="@no"/></td>
    > <td><xsl:value-of select="@level"/></td>
    > </tr>
    > </xsl:if>
    > </xsl:for-each>
    >
    > </table>
    >
    > <!-- now goes level 2-->
    >
    > <table align="center" border="1">
    > <tr>
    > <th>Name</th><th>No.</th><th>Level</th>
    > </tr>
    >
    > <xsl:for-each select="//node">
    > <xsl:sort select="@level"/>
    >
    > <xsl:if test="@level='2'">
    > <tr>
    > <td align="center"><xsl:value-of select="name()"/></td>
    > <td><xsl:value-of select="@no"/></td>
    > <td><xsl:value-of select="@level"/></td>
    > </tr>
    > </xsl:if>
    > </xsl:for-each>
    >
    > </table>
    > </body>
    > </html>
    >
    > </xsl:template>
    >
    > </xsl:stylesheet>
    >
    > It works fine but it's useless when there would be more then 2 levels -

    how
    > can i loop this template to go through all the levels - each level has a

    new
    > table(just like above)
    >
    > and second thing how can i count node with e.g. attributes level="2"?
    >
    > I've tried sth like this:
    > <xsl:template match="/">
    > <xsl:variable name="ile" select="count(//node@level='2')" />
    > </xsl:template>
    >
    > and then:
    >
    > <b><xsl:value-of select="$ile"/></b>
    >
    > but it's wrong and i've got warning msg.
    >
    > thanks in advance
    > greetings R
    >
    >
    > ---
    > Outgoing mail is certified Virus Free.
    > Checked by AVG anti-virus system (http://www.grisoft.com).
    > Version: 6.0.554 / Virus Database: 346 - Release Date: 03-12-20
    >
    >
    Dimitre Novatchev, Dec 30, 2003
    #2
    1. Advertising

  3. Ruthless

    Ruthless Guest

    Wow man

    It will take me all night to understand your example ;D

    but thanks, you helped me a lot

    greetings R

    U¿ytkownik "Dimitre Novatchev" <> napisa³ w wiadomo¶ci
    news:bsrena$k0j6$-berlin.de...
    > The way to do this is the following:
    >
    > This transformation:
    >
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    >
    > <xsl:template match="/">
    > <html>
    > <body>
    > <xsl:apply-templates/>
    > </body>
    > </html>
    > </xsl:template>
    >
    > <xsl:template match="*[node]">
    > <table align="center" border="1">
    > <tr>
    > <th>Name</th><th>No.</th><th>Level</th>
    > <xsl:apply-templates select="node" mode="display"/>
    > </tr>
    > </table>
    > <br />
    > <br />
    > <xsl:apply-templates select="node"/>
    > </xsl:template>
    >
    > <xsl:template match="node" mode="display">
    > <tr>
    > <td align="center"><xsl:value-of select="name()"/></td>
    > <td><xsl:value-of select="@no"/></td>
    > <td><xsl:value-of select="@level"/></td>
    > </tr>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    > When applied on this source.xml:
    >
    > <struct>
    > <node level="1" no="1">
    > <node level="2" no="2" />
    > <node level="2" no="3">
    > <node level="3" no="4"/>
    > </node>
    > <node level="2" no="5" />
    > </node>
    > <node level="1" no="6">
    > <node level="2" no="7">
    > <node level="3" no="8"/>
    > <node level="3" no="9"/>
    > </node>
    > <node level="2" no="10" />
    > <node level="2" no="11" />
    > </node>
    > </struct>
    >
    > Produces this output (as displayed in the browser):
    >
    > Name No. Level
    >
    > node 1 1
    >
    > node 6 1
    >
    >
    >
    >
    > Name No. Level
    >
    > node 2 2
    >
    > node 3 2
    >
    > node 5 2
    >
    >
    >
    >
    > Name No. Level
    >
    > node 4 3
    >
    >
    >
    >
    > Name No. Level
    >
    > node 7 2
    >
    > node 10 2
    >
    > node 11 2
    >
    >
    >
    >
    > Name No. Level
    >
    > node 8 3
    >
    > node 9 3
    >
    >
    > However you want all nodes belonging to the same level to be displayed in

    a
    > single table.
    >
    > In this case this transformation:
    >
    >
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    >
    > <xsl:key name="kByLevel" match="node" use="@level"/>
    >
    > <xsl:variable name="vMinMaxLevel">
    > <xsl:for-each
    > select="//node[generate-id()
    > =
    > generate-id(key('kByLevel', @level)[1])
    > ]">
    > <xsl:sort select="@level" data-type="number"/>
    >
    > <xsl:if test="position() = 1 or position() = last()">
    > <xsl:value-of select="@level"/>
    > <xsl:if test="position() = 1">|</xsl:if>
    > </xsl:if>
    > </xsl:for-each>
    > </xsl:variable>
    >
    > <xsl:template match="/">
    > <xsl:call-template name="displayH">
    > <xsl:with-param name="pLevel"
    > select="substring-before($vMinMaxLevel, '|')"/>
    > <xsl:with-param name="pMaxLevel"
    > select="substring-after($vMinMaxLevel, '|')"/>
    >
    > </xsl:call-template>
    > </xsl:template>
    >
    > <xsl:template name="displayH">
    > <xsl:param name="pLevel" select="1"/>
    > <xsl:param name="pMaxLevel" select="1"/>
    >
    > <xsl:variable name="vThisLevel"
    > select="key('kByLevel', $pLevel)"/>
    >
    > <xsl:if test="$pLevel &lt;= $pMaxLevel
    > and $vThisLevel">
    > <table align="center" border="1">
    > <tr>
    > <th>Name</th><th>No.</th><th>Level</th>
    > <xsl:apply-templates select="$vThisLevel"/>
    > </tr>
    > </table>
    > <br />
    > <br />
    > <xsl:call-template name="displayH">
    > <xsl:with-param name="pLevel" select="$pLevel + 1"/>
    > <xsl:with-param name="pMaxLevel" select="$pMaxLevel"/>
    > </xsl:call-template>
    > </xsl:if>
    > </xsl:template>
    >
    > <xsl:template match="node">
    > <tr>
    > <td align="center"><xsl:value-of select="name()"/></td>
    > <td><xsl:value-of select="@no"/></td>
    > <td><xsl:value-of select="@level"/></td>
    > </tr>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    >
    > when applied on the same source.xml produces the wanted output:
    >
    > Name No. Level
    >
    > node 1 1
    >
    > node 6 1
    >
    >
    > Name No. Level
    >
    > node 2 2
    >
    > node 3 2
    >
    > node 5 2
    >
    > node 7 2
    >
    > node 10 2
    >
    > node 11 2
    >
    >
    > Name No. Level
    >
    > node 4 3
    >
    > node 8 3
    >
    > node 9 3
    >
    >
    > This transformation works even in cases when levels are not consecutive
    > numbers (or even positive numbers) and when we do not know the starting
    > level.
    >
    > Hope this helped.
    >
    > Dimitre Novatchev.
    > FXSL developer, XML Insider,
    >
    > http://fxsl.sourceforge.net/ -- the home of FXSL
    > Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
    >
    >
    > "Ruthless" <ruthless@NO_SPAM.poczta.onet.pl> wrote in message
    > news:bsq92m$3p5$...
    > > Hello.
    > >
    > > I've got a simple XML:
    > >
    > > <?xml version="1.0" encoding="iso-8859-2"?>
    > > <?xml-stylesheet type="text/xsl" href="4.xsl"?>
    > >
    > > <struct>
    > >
    > > <node level="1" no="1">
    > >
    > > <node level="2" no="2" />
    > > <node level="2" no="3" />
    > > <node level="2" no="4" />
    > > </node>
    > >
    > > <node level="1" no="5">
    > >
    > > <node level="2" no="6" />
    > > <node level="2" no="7" />
    > > <node level="2" no="8" />
    > > </node>
    > >
    > > </struct>
    > >
    > > and i want to display all the levels starting from 1 to 2
    > >
    > > I've got my xslt sth like this:
    > >
    > > <?xml version="1.0" encoding="ISO-8859-2" ?>
    > > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    > > version="1.0">
    > >
    > > <xsl:eek:utput method="html"/>
    > >
    > > <xsl:template match="/">
    > >
    > > <html>
    > > <body>
    > >
    > > <table align="center" border="1">
    > > <tr>
    > > <th>Name</th><th>No.</th><th>Level</th>
    > > </tr>
    > >
    > > <xsl:for-each select="//node">
    > > <xsl:sort select="@level"/>
    > >
    > > <xsl:if test="@level='1'">
    > > <tr>
    > > <td align="center"><xsl:value-of select="name()"/></td>
    > > <td><xsl:value-of select="@no"/></td>
    > > <td><xsl:value-of select="@level"/></td>
    > > </tr>
    > > </xsl:if>
    > > </xsl:for-each>
    > >
    > > </table>
    > >
    > > <!-- now goes level 2-->
    > >
    > > <table align="center" border="1">
    > > <tr>
    > > <th>Name</th><th>No.</th><th>Level</th>
    > > </tr>
    > >
    > > <xsl:for-each select="//node">
    > > <xsl:sort select="@level"/>
    > >
    > > <xsl:if test="@level='2'">
    > > <tr>
    > > <td align="center"><xsl:value-of select="name()"/></td>
    > > <td><xsl:value-of select="@no"/></td>
    > > <td><xsl:value-of select="@level"/></td>
    > > </tr>
    > > </xsl:if>
    > > </xsl:for-each>
    > >
    > > </table>
    > > </body>
    > > </html>
    > >
    > > </xsl:template>
    > >
    > > </xsl:stylesheet>
    > >
    > > It works fine but it's useless when there would be more then 2 levels -

    > how
    > > can i loop this template to go through all the levels - each level has a

    > new
    > > table(just like above)
    > >
    > > and second thing how can i count node with e.g. attributes level="2"?
    > >
    > > I've tried sth like this:
    > > <xsl:template match="/">
    > > <xsl:variable name="ile" select="count(//node@level='2')" />
    > > </xsl:template>
    > >
    > > and then:
    > >
    > > <b><xsl:value-of select="$ile"/></b>
    > >
    > > but it's wrong and i've got warning msg.
    > >
    > > thanks in advance
    > > greetings R
    > >
    > >
    > > ---
    > > Outgoing mail is certified Virus Free.
    > > Checked by AVG anti-virus system (http://www.grisoft.com).
    > > Version: 6.0.554 / Virus Database: 346 - Release Date: 03-12-20
    > >
    > >

    >
    >
    >



    ---
    Outgoing mail is certified Virus Free.
    Checked by AVG anti-virus system (http://www.grisoft.com).
    Version: 6.0.554 / Virus Database: 346 - Release Date: 03-12-20
    Ruthless, Dec 30, 2003
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fred
    Replies:
    1
    Views:
    594
    Neredbojias
    Sep 26, 2005
  2. John Harrison

    using templates in templates

    John Harrison, Jul 31, 2003, in forum: C++
    Replies:
    8
    Views:
    379
    Torsten Curdt
    Jul 31, 2003
  3. JKop
    Replies:
    3
    Views:
    467
  4. recover
    Replies:
    2
    Views:
    799
    recover
    Jul 25, 2006
  5. Replies:
    5
    Views:
    271
Loading...

Share This Page