xsl-list
[Top] [All Lists]

RE: Traversing the tree

2005-09-10 09:17:19
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*(_at_)qty over a set of sibling elements:

<xsl:template match="order">
  <total-value>
    <xsl:apply-template select="order-item[1]">
      <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[1]">
      <xsl:with-param name="running-total" select="$running-total +
(@price*(_at_)qty)"/>
    </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$running-total + (@price*(_at_)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(_at_)yahoo(_dot_)com] 
Sent: 09 September 2005 21:31
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: Re: [xsl] 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(_at_)yahoo(_dot_)com> 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/

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--





--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



<Prev in Thread] Current Thread [Next in Thread>