RE: Traversing the tree
This kind of problem is best tackled using recursion. It's difficult to write your first recursive stylesheet, but it's a very powerful technique to have under your belt. Basically you need to write a template that processes one of the siblings, passing it the value of your "counter" or "running-total" as a parameter. The template needs to make whatever changes are necessary to the counter or running total, then make a recursive call to process the next element if there is one, passing the new value of the counter or running total as a parameter. When the final sibling is reached, you return (or write to the output) the final value of the counter. You can do this either with call-template or apply-templates (perhaps using a special mode). I find it easier to use apply-templates, for two reasons: (a) the current node is passed as an implicit parameter, and (b) the recursion often terminates naturally when there are no more siblings. Here's an example that totals @price*@qty over a set of sibling elements: <xsl:template match="order"> <total-value> <xsl:apply-template select="order-item"> <xsl:with-param name="running-total" select="0"/> </xsl:apply-templates> </total-value> </xsl:template> <xsl:template match="order-item"> <xsl:param name="running-total"/> <xsl:choose> <xsl:when test="following-sibling::order-item"> <xsl:apply-template select="following-sibling::order-item"> <xsl:with-param name="running-total" select="$running-total + (@price*@qty)"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <xsl:value-of select="$running-total + (@price*@qty)"/> </xsl:otherwise> </xsl:choose> </xsl:template> I hope you can see how to adapt this technique to your problem. Michael Kay http://www.saxonica.com/ > -----Original Message----- > From: Agnisys Technology (P) Ltd. [mailto:agnisys@xxxxxxxxx] > Sent: 09 September 2005 21:31 > To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx > Subject: Re: Traversing the tree > > David, > My real problem is a little more complex as it turns out, > and I'm stuck again! > What if instead of using the count or sum functions, I need > to use my own function for each of > the nodes after the one with an "offset"? Can I still use > some creative Xpath operation? > > For example: > Input: > > <top> > <a> > <reg > A1 </reg> > <reg offset="5" > A2 </reg> > <reg > A3 </reg> > <section> > section_foo > </section> > <section> > section_bar > </section> > <reg > A4 </reg> > </a> > </top> > > Assume there is a "sizeNode" function that returns a "size" > of "section". > sizeNode(section_foo) = 10 > sizeNode(section_bar) = 100 > > So, the output of the above should be : > A1 : 0 > A2 : 5 > A3 : 6 > section_foo : 7 > section_bar : 17 > A4 : 117 > > So now I cannot use the following because the "size" of each > "section" could be different. > sum($x/@offset) + > (count(preceding-sibling::reg|preceding-sibling::section) - > count($x/preceding-sibling::reg|preceding-sibling::section)) > > I need some way to add up "size"s of all the nodes after (and > including) the node with an "offset" > attribute. > > Once again I'm tempted to use a for loop and have a running > counter, but I'm sure there is a > better way. > > I would appreciate any help/pointer in this regard. > Anupam. > > P.S: Jay thanks for your effort, for me it was more food for thought. > > > --- "Agnisys Technology (P) Ltd." <agnisys@xxxxxxxxx> wrote: > > > David, > > Your alternate strategy works well and solves the problem. > > Although, I do need to study it carefully to understand > how it is doing it! > > Thanks, > > Anupam. > > > > > > > > ______________________________________________________ > Click here to donate to the Hurricane Katrina relief effort. > http://store.yahoo.com/redcross-donate3/
PURCHASE STYLUS STUDIO ONLINE TODAY!
Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!
Download The World's Best XML IDE!
Accelerate XML development with our award-winning XML IDE - Download a free trial today!
Subscribe in XML format