Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > XML > XSLT
Password Reminder
Register
| FAQ | Members List | Search | Today's Posts | Mark Forums Read
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developers’ questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old January 2nd, 2007, 01:42 PM
Registered User
 
Join Date: Jan 2007
Location: , , .
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
Default recursion in XSL

Hello All,

I have been experiencing some problems while trying to write a recursive template in XSL.
The formatting of my xml docs is as follows:

<nestedElement>
<tagName>tag</tagName>
<someTag>
<nestedElement>
<tagName>test</tagName>
<fieldAttribute>
<name>attribute1</name>
<var>temp</var>
</fieldAttribute>
<nestedElement>
<tagName>test1</tagName>
</nestedElement>
</nestedElement>
</nestedElement>

The template should loop through all the nestedElements, and the path in which the template is enterng should be stored in a variable. Still I can't get this to work for some weird reason. As far as I can get is this code.

<xsl:template name="nestedElement">
<xsl:param name="level" select="nestedElement" />
<xsl:for-each select="$level">
<xsl:variable name="nestedElementName" select="tagName" />
//this element is the output I want, together with the attributes that will be processed by the template underneath it
<xsl:element name="{$nestedElementName}">
<xsl:call-template name="fieldAttribute" />
<xsl:value-of select="testvalue" />
</xsl:element>

//I use this test for checking whether there is another element nested.. if so, recursion should occur.

<xsl:if test="nestedElement/tagName != """>
<xsl:variable name="nextlevel" />

//I tried to add this attriubte: select", "concat ($level, '/nestedElement')", but gives an error..

<xsl:call-template name="nestedElement">
    <xsl:with-param name="level" />
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:template>

//this is the template for the fieldAttribute resolving
<xsl:template name="fieldAttribute">
<xsl:for-each select="fieldAttribute">
<xsl:variable name="tempname" select="name" />
<xsl:variable name="tempvalue" select="var" />
<xsl:attribute name="{$tempname}">
<xsl:copy-of select="$tempvalue" />
</xsl:attribute>
</xsl:for-each>
</xsl:template>

the variable nextlevel should store the current root level, e.g.
nestedElement/nestedElement, and increment each time the loop is entering a new child node.. each 'nestedElement' created with the variable nestedElementName should be nested in its appropriate level..

output should be like

<tag1>
<test attribute1='temp'>
<test1></test1>
</tagName>
</tagName>

as far as this code is, the template (with some changes) works for two levels

I would of have doen this by passing that variable as parameter with the new call.

Stills IE keeps giving errors about the undefined variable level..
or something about only one element being able to exist in the top node?

for a quick look at the whole thing.. it is online at
http://onuris.groept.be/ENG/eTech/a0...gister_kot.php

anyone has any ideas on this one? Took me a lot of time to sort it out

thanks in advance,

Jeroen
Reply With Quote
  #2 (permalink)  
Old January 2nd, 2007, 02:47 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

I think this:

<xsl:if test="nestedElement/tagName != """>

should simply be

<xsl:if test="tagName">

to test if the context item has a child called tagName. (But I may have misunderstood your logic).

//I tried to add this attriubte: select", "concat ($level, '/nestedElement')", but gives an error..

I'm not sure where you tried to put it, and you haven't told us what the error message was, so it's hard to help. However, it looks a bit to me as if you're trying to construct XPath expressions dynamically. You can't do that in standard XSLT (well, you can, but there's no way to evaluate them without an extension function such as saxon:evaluate()). This sounds like the wrong design approach. So perhaps it would be best to go back to first principles: what are you actually trying to achieve?

>Stills IE keeps giving errors about the undefined variable level..

Please quote actual error messages. You might not understand them, but there's a good chance that someone else will.

Also, please note that IE is about the worst XSLT development environment you could possibly choose. Its error messages are notoriously poor. It's fine for deploying your stylesheets once they work, but not for developing and debugging.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
Reply With Quote
  #3 (permalink)  
Old January 2nd, 2007, 02:58 PM
Registered User
 
Join Date: Jan 2007
Location: , , .
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
Default

<b>Notice</b>: Undefined variable: level in <b>D:\Websites\ENG\eTech\a06_eTech08\kotModule.php </b> on line <b>188</b><br />
^
This is the error I get when adding the following attribute to my variable (see template code in previous post)
<xsl:variable name="nextlevel" select="concat($level, '/nestedElement')" />

So I just meant the select attribute. or maybe I should get the value-of select="$level" first and then do the concat?

And yes, I think I would like to have some kind of dynamic XPath reference to run the following statement
<xsl:for-each select="$level">

where level should recursively increase, according to the number of elements nested..
e.g. I have three levels of nested elements,
[u]first:</u> $level should first select the parent node (so it should have the value /nestedElement)
[u]second:</u> it should select the first child (path is /nestedElement/nestedElement),
[u]finally:</u> process the last ($level is /nestedElement/nestedElement/nestedElement)..
is this truly impossible?

thanks for your help alright.
Reply With Quote
  #4 (permalink)  
Old January 2nd, 2007, 04:08 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Can't see why you would get this error, it's presumably because I'm not seeing the whole code.

As I say, I think you need a completely different approach to this problem, so it would help to explain what you are trying to do. The sample output you've shown

<tag1>
 <test attribute1='temp'>
  <test1></test1>
 </tagName>
</tagName>

isn't well-formed XML, so I've really very little idea what your requirements are.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
Reply With Quote
  #5 (permalink)  
Old January 2nd, 2007, 04:35 PM
Registered User
 
Join Date: Jan 2007
Location: , , .
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
Default

My mistake, it should be like this.

<tag1>
 <test>
  <test1></test1>
 </test>
</tag1>

The nestedElement template should iterate a nestedElement tree.
the input could be

<nestedElement>
 <tagName>tag1</tagName>
 <nestedElement>
  <tagName>test</tagName>
  <nestedElement>
   <tagName>test1</tagName>
  </nestedElement>
 </nestedElement>
</nestedElement>

the template should select each child with the next recusrion, and create an element with the textnode of the tagName element in that node. I hope that this clarifies my idea.

I try to store the path expression in a variable, so somehow the template know where he left the tree when the next recursion occurs..

I hope you get the idea firt..

last try from me :

<xsl:template name="nestedElement">
  <xsl:param name="level" select="'nestedElement'" />
  <xsl:variable name="nextlevel" select="concat()"/>
 <xsl:for-each select="$level">


so the level variable should go through the three directories
first it should select th first nestedElement in the for-each
second it should select the nestedElement/nestedElement
and third it should select the nestedElement/nestedElement/nestedElement with the for-each statement

so I should have some variable to track what the last path was and then get the path to his nestedElement children if there there are nestedElement children in the that selected node.. that's it

I he can't resolve the variable under the for-each because the level variable will be behind a x directories after x recursions.. maybe that's why he can't resolve? the for-each select statement is variable..?

thanks a lot for your help so far


Reply With Quote
  #6 (permalink)  
Old January 2nd, 2007, 04:50 PM
Registered User
 
Join Date: Jan 2007
Location: , , .
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I think I should get the path to the node where the for-each statement is in every recursion.

or just the value of $level in the for-each statement..



Reply With Quote
  #7 (permalink)  
Old January 2nd, 2007, 05:22 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

I think you're making it far too complicated. So far it looks like this:

<xsl:template match="nestedElement"/>
  <xsl:apply-templates select="tagName"/>
</xsl:template>

<xsl:template match="tagName">
  <xsl:element name="{.}">
    <xsl:apply-templates select="following-sibling::nestedElement"/>
  </xsl:element>
</xsl:element>

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
Reply With Quote
  #8 (permalink)  
Old January 2nd, 2007, 05:39 PM
Registered User
 
Join Date: Jan 2007
Location: , , .
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Okay thank you, looks nice and simple..

but what do I have to do if the nestedElement aren't root elements in my xml?

that doesn't seem to work so far..



Reply With Quote
  #9 (permalink)  
Old January 2nd, 2007, 06:16 PM
Registered User
 
Join Date: Jan 2007
Location: , , .
Posts: 6
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Sorry to bother you with maybe these simple questions.. but I'm pretty new to xsl, and I dont have an idea about how to make the most optimal design.

also for the nestedElements, each time there can be several attributeFields as children. These should be processed to with the template I wrote above. the tags are

<fieldAttribute>
 <name>attributename</name>
 <var>value</value>
</fieldAttribute>

I tried what you said, it works Okay, but then the attributes aren't added.
Your solution also works for one level of nestedElements, the children of the first one don't seem to get in there.
another example from my xml:

<nestedElement>
 <nestedElement>
  <tagName>option</tagName>
  <testvalue>Zwarte Zustersstraat</testvalue>
  <fieldAttribute>
   <name>value</name>
   <var>Zwarte Zustersstraat</var>
  </fieldAttribute>
 </nestedElement>
 <tagName>select</tagName>
 <fieldAttribute>
   <name>value</name>
   <var>Zwarte Zustersstraat</var>
 </fieldAttribute>
</nestedElement>

thanks for your time!

Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
xsl recursion problem vinayreddy XSLT 5 August 14th, 2008 07:14 AM
Recursion lincsimp XSLT 1 August 16th, 2005 04:26 PM
recursion yui0329 C# 6 April 28th, 2005 09:36 AM
Recursion shan9 JSP Basics 0 November 17th, 2004 09:29 PM
recursion nulogix PHP How-To 1 June 28th, 2004 03:58 PM



All times are GMT -4. The time now is 08:11 AM.


Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.