Recusion in XSL with nested XML

oooooo0000000

Usenet Archive
Joined
Aug 18, 2004
Messages
2
Reaction score
0
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
 

Johannes Koch

Usenet Archive
Joined
Nov 14, 2000
Messages
801
Reaction score
0
oooooo0000000 said:
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.
 

Marrow (2)

Usenet Archive
Joined
Nov 19, 2003
Messages
37
Reaction score
0
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:eek:utput 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
 

Robin Johnson

Usenet Archive
Joined
Oct 26, 2000
Messages
25
Reaction score
0
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>
 

oooooo0000000

Usenet Archive
Joined
Aug 18, 2004
Messages
2
Reaction score
0
I have an XML file of varying nesting depth...
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
 

kahrs

Usenet Archive
Joined
Aug 18, 2004
Messages
4
Reaction score
0
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.
 

Marrow (2)

Usenet Archive
Joined
Nov 19, 2003
Messages
37
Reaction score
0
Errrrmmm, don't use for-each to begin with? ;)

oooooo0000000 said:
(oooooo0000000) wrote:

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
 

William Park

Usenet Archive
Joined
Jul 5, 2002
Messages
213
Reaction score
0
oooooo0000000 said:
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

You've been given other answers. If you're adventurous, here is Bash shell solution.

start {
case $1 in
item) declare "$@"; itemid=$id ;;
name) printf "%*c %s name\n" $XML_ELEMENT_DEPTH ' ' $itemid ;; esac } xml -s start "<catalouge>...</catalouge>"

Ref:
man 3 printf :)
http://freshmeat.net/projects/bashdiff/
help xml
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
548,208
Messages
3,104,799
Members
249,594
Latest member
henrywalsh

Latest Threads

Top