469,322 Members | 1,093 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,322 developers. It's quick & easy.

Recusion in XSL with nested XML

I have an XML file of varying nesting depth...

<catalouge>
<item id="1">
<name/>
<item id="23">
<name/>
<item id="55">
<name/>
</item>
</item>
<item id="7">
<name/>
</item>
</catalouge>

So, each item can contain many items.

I'm trying to get my XSLT to recursivly loop through each item to
print it out in block quotes eg
1 name
23 name
55 name
7 name

How can I get a <xsl:for-each> loop to go through the whole tree?

Thanks

Yours, in confusion

o0
Jul 20 '05 #1
6 2007
Hi,

Whenever you are dealing with common elements that appear at nested levels
it is usually best to avoid for-each and go for a recursive push approach
using applied templates, e.g....

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="catalouge">
<html>
<body>
<xsl:apply-templates select="item"/>
</body>
</html>
</xsl:template>

<xsl:template match="item">
<blockquote>
<xsl:value-of select="@id"/>
<xsl:text> </xsl:text>
<xsl:value-of select="name"/>
<xsl:apply-templates select="item"/>
</blockquote>
</xsl:template>
</xsl:stylesheet>

HTH
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator
"oooooo0000000" <oo***********@yahoo.com.au> wrote in message
news:41**************************@posting.google.c om...
I have an XML file of varying nesting depth...

<catalouge>
<item id="1">
<name/>
<item id="23">
<name/>
<item id="55">
<name/>
</item>
</item>
<item id="7">
<name/>
</item>
</catalouge>

So, each item can contain many items.

I'm trying to get my XSLT to recursivly loop through each item to
print it out in block quotes eg
1 name
23 name
55 name
7 name

How can I get a <xsl:for-each> loop to go through the whole tree?

Thanks

Yours, in confusion

o0

Jul 20 '05 #2
oooooo0000000 wrote:
I have an XML file of varying nesting depth...

<catalouge>
<item id="1">
<name/>
<item id="23">
<name/>
<item id="55">
<name/>
</item>
</item>
<item id="7">
<name/>
</item>
</catalouge>

So, each item can contain many items.

I'm trying to get my XSLT to recursivly loop through each item to
print it out in block quotes eg


I hope you don't mean the HTML blockquote element, which is semantically
most probably inappropriate for this purpose (as the name says, it's for
a long block of quotation). Nested lists (ol/ul) would be much better.
If you want to indent text, use CSS.
--
Johannes Koch
In te domine speravi; non confundar in aeternum.
(Te Deum, 4th cent.)
Jul 20 '05 #3
oo***********@yahoo.com.au (oooooo0000000) wrote in message news:<41**************************@posting.google. com>...
I have an XML file of varying nesting depth...

<catalouge>
<item id="1">
<name/>
<item id="23">
<name/>
<item id="55">
<name/>
</item>
</item>
<item id="7">
<name/>
</item>
</catalouge>

So, each item can contain many items.

I'm trying to get my XSLT to recursivly loop through each item to
print it out in block quotes eg
1 name
23 name
55 name
7 name

How can I get a <xsl:for-each> loop to go through the whole tree?


Easy; don't. Use apply-templates. If you make this a general habit you
will write much more efficient code. I think this does it in 1.0:

(A quick hack, and untested; there is probably a more efficient way
even if it works, but you get the idea.)

<xsl:template match="item">
<xsl:apply-templates select="*">
</xsl:template>

<!-- if you're doing what I think you're doing (?) -->
<xsl:template match="item/*[not(self::item)]">
<!--
one of the few occasions I'll use for-each,
and even then I'd be more inclined to use a 'repeat'
subtemplate with count(ancestor::item) supplied as a parameter
-->
<xsl:for-each select="ancestor::item">
<xsl:text> </xsl:text>
</xsl:for-each>

<xsl:value-of select="concat(parent::item/@id, ' ', name())"/>
<xsl:text>
</xsl:text><!-- output an EOL character - I hate breaking indent
style to do that, so I usually use a global
text variable called $EOL or similar -->
</xsl:template>

--
Robin Johnson
Lead Developer, enCircle Solutions Ltd.
first initial last name at encircle dot co dot uk
Jul 20 '05 #4
oo***********@yahoo.com.au (oooooo0000000) wrote in message news:<41**************************@posting.google. com>...
I have an XML file of varying nesting depth... <SNIP>
How can I get a <xsl:for-each> loop to go through the whole tree?


Ok, so I can use <xsl:for-each select="//item"> to pick up all of the
items (hurrah!) and I can use other XPATHs to get all the children of
a particular node.

But, how do I go about "unbalancing" the blockquotes?

I want

parent
child
grandchild
other child

etc. so I tried to use

<xsl:template match="/">
<xsl:for-each select="//item">
<BLOCKQUOTE>
<xsl:value-of select="title"/>
</xsl:for-each>
</BLOCKQUOTE>
</xsl:template>

and, of course, with the tags out of order it doesn't work. My brain
is telling me I'm missing something staggeringly obvious... any clues?

Thank

o0
Jul 20 '05 #5
Hello,

it is interesting to see that you are talking
about recursion although such XML structures
are just ordinary trees. Below you find a non-
recursive solution.
I'm trying to get my XSLT to recursivly loop through each item to
print it out in block quotes eg
1 name
23 name
55 name
7 name

You asked for a solution in XSL.
I hope you wont flame me if I post a solution
in a different language. This is a GNU AWK
script which I have tested:

BEGIN { XMLMODE=1 }
XMLSTARTELEM { Depth++ }
XMLSTARTELEM == "item" { id=XMLATTR["id"] }
XMLSTARTELEM == "name" { printf("%*s %s\n", 2*Depth, id, "name" ) }
XMLENDELEM { Depth-- }

As I said, this one is tested and works, producing
correctly indented lines:

1 name
23 name
55 name
7 name
How can I get a <xsl:for-each> loop to go through the whole tree?


In AWK, traversing the tree is the default behavior,
therefore no recursion is needed.
Jul 20 '05 #6
Errrrmmm, don't use for-each to begin with? ;)

"oooooo0000000" <oo***********@yahoo.com.au> wrote in message
news:41**************************@posting.google.c om...
oo***********@yahoo.com.au (oooooo0000000) wrote in message

news:<41**************************@posting.google. com>...
I have an XML file of varying nesting depth...

<SNIP>

How can I get a <xsl:for-each> loop to go through the whole tree?


Ok, so I can use <xsl:for-each select="//item"> to pick up all of the
items (hurrah!) and I can use other XPATHs to get all the children of
a particular node.

But, how do I go about "unbalancing" the blockquotes?

I want

parent
child
grandchild
other child

etc. so I tried to use

<xsl:template match="/">
<xsl:for-each select="//item">
<BLOCKQUOTE>
<xsl:value-of select="title"/>
</xsl:for-each>
</BLOCKQUOTE>
</xsl:template>

and, of course, with the tags out of order it doesn't work. My brain
is telling me I'm missing something staggeringly obvious... any clues?

Thank

o0

Jul 20 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

reply views Thread by Glen | last post: by
6 posts views Thread by Andy Baker | last post: by
3 posts views Thread by Erik Bongers | last post: by
6 posts views Thread by B0nj | last post: by
8 posts views Thread by Robert W. | last post: by
3 posts views Thread by jdurancomas | last post: by
29 posts views Thread by Barry | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
reply views Thread by Gurmeet2796 | last post: by
reply views Thread by harlem98 | last post: by
reply views Thread by listenups61195 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.