By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,831 Members | 1,024 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,831 IT Pros & Developers. It's quick & easy.

looping templates

P: n/a
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:output 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
Jul 20 '05 #1
Share this Question
Share on Google+
2 Replies


P: n/a
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:bs**********@nemesis.news.tpi.pl...
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:output 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


Jul 20 '05 #2

P: n/a
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" <dn********@yahoo.com> napisał w wiadomo¶ci
news:bs***********@ID-152440.news.uni-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:bs**********@nemesis.news.tpi.pl...
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:output 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
Jul 20 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.