Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
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 software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old May 9th, 2010, 04:13 AM
Authorized User
 
Join Date: May 2010
Posts: 16
Thanks: 0
Thanked 0 Times in 0 Posts
Default Counter within nested for-each

I am getting back into XSL after about a 4 year absence.

I've been trying to track down a solution to the following (common, I suppose) question. It's related to counting nodes within nested for-each loops. It's for handling page-break logic where I need to know how many pages will be generated and putting a certain amount of rows/nodes on a page.

Sample XML:

<Root>

<Main>

<Sub1>

<Sub2>xxx</Sub2>
<Sub2>yyy</Sub2>
<Sub2>zzz</Sub2>
</Sub1>
<Sub1>

<Sub2>aaa</Sub2>
<Sub2>bbb</Sub2>
<Sub2>ccc</Sub2>
</Sub1>
</Main>
</Root>

I first count all the all 'Sub2' nodes across all 'Sub1' siblings for 'Main' - I correctly get 6 (i.e. count(.//Sub2).

I use for-each loops on Sub1, then Sub2.

<xsl:for-each select="Sub1">
<xsl:for-each select="Sub2">
... Do some stuff here...

...Need to keep track of position/count of ALL Sub2 nodes for breaking logic (i.e. count from 1-6)...
...
</xsl:for-each>

<xsl:call-template name="createSub1Totalline"/>

</xsl:for-each>

I need to do breaks on each 'Sub1' but I need to keep track of all 'Sub2' . I try to use position() but since it keeps track of position
relative to the node context I get 1,2,3.... 1,2,3 What I want is 1,2,3,4,5,6

Is my question clear? I've seen a variety of very confusing code for something that "seems" so trivial. Not for me!

Any help is appreciated.

Thanks.

Rob
 
Old May 9th, 2010, 07:18 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Consider to show us the sample output you want to generate for the sample input you posted and to explain in plain English how the input is mapped to the output. Then we can try to show an XSLT way of achieving that.
If you want to count the preceding "Sub2" elements plus the one which is the context node in the inner for-each then you can simply use
Code:
count(preceding::Sub2) + 1
Then for counting or numbering element or nodes in general XSLT has the powerful xsl:number so doing e.g.
Code:
<xsl:variable name="c"><xsl:number level="any"/></xsl:variable>
might also give you the number you want.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old May 9th, 2010, 03:26 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

<xsl:number level="any" from="Main"/> might do the trick. However, when the problem is to create a break when a value reaches some threshold, and then reset the accumulated value to zero, the solution often involves recursive processing of the list of items, passing the accumulated total as a parameter on the recursive call.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old May 10th, 2010, 01:23 AM
Authorized User
 
Join Date: May 2010
Posts: 16
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thank you Martin and Michael.

Martin: re: count(preceding::Sub2) + 1
I had actually tried a similar approach and it does give me a correct "full" count however, as Michael points out I do need to create a break when a value reaches some threshold, and then reset the accumulated value to zero.

Let me try once again to give you a better picture. There are actually three for-each loops, processing multiple MAINs.

<Root>
<Main>
<Sub1>
<Sub2></Sub2>
<Sub2></Sub2>
<Sub2></Sub2>
</Sub1>
<Sub1>
<Sub2></Sub2>
<Sub2></Sub2>
<Sub2></Sub2>
</Sub1>
</Main>
<Main>
<Sub1>
<Sub2></Sub2>
<Sub2></Sub2>
<Sub2></Sub2>
<Sub2></Sub2>
<Sub2></Sub2>
</Sub1>
<Sub1>
<Sub2></Sub2>
<Sub2></Sub2>
</Sub1>
</Main>
</Root>


<xsl:for-each select="Main">
...do stuff for each Main...

<xsl:for-each select="Sub1">
...do stuff for each Sub1...
++ Want to init (reinit) with new Sub2 count ++

<xsl:for-each select="Sub2">
<p><xsl:value-of select="count(preceding::Sub2) + 1" /></p>
...do stuff for each Sub2...
++ NOW: Check how many TOTAL Sub2s have been processed across all Sub1s; break when needed ++
</xsl:for-each>

<xsl:call-template name="setupTotalsForSub1"/>
</xsl:for-each>

<xsl:call-template name="setupGrandTotalsForMain"/>
</xsl:for-each>

So, first pass through is correct - i.e. 1,2,3,4,5,6; however, when the next Main is processed it begins with 7, 8, 9, etc

Need to reset the counter. I even tried to use XSL:Script to create a counter (against Michael's advice in XSLT 2nd Ed) but I could not get past name-space errors and decided not to spend more time on that.

I hope I am being clearer this time.

Thanks.
Rob
 
Old May 21st, 2010, 01:54 AM
Authorized User
 
Join Date: May 2010
Posts: 16
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Wondering if my last post made sense to anyone and if you think recursion is the only way to handle this.

Thanks.
Rob
 
Old May 21st, 2010, 02:22 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

Firstly, you haven't actually given us an example of what you want your output XML to look like.

If you use <xsl:for-each select="Sub1/Sub2"> and position() you get 1 to 6, then 1 to 7.
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
 
Old May 21st, 2010, 03:02 AM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 291
Thanks: 9
Thanked 29 Times in 29 Posts
Thumbs up

Please post your complete xslt code and the expected output from the transformation. That would help someone here to give you the solution.
__________________
Rummy
 
Old May 21st, 2010, 03:14 AM
Authorized User
 
Join Date: May 2010
Posts: 16
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I hope the following example will help w/my question:

http://share.rjfweb.com/XML/ProcessP...FinSample3.xml

Notice there is a count (from 1-180) which is the result of
<p> <xsl:value-of select="count(preceding::Sub2) + 1" /> </p>

That sequence is correct. That is the same sequence I need for the "Par Amount" in the yellow table below it. Notice it goes from 1-174; then 1-3; 1-3. I cannot use the same (1-180) counter since the *following* sequence picks up from 181... I need this to restart at 1. Again, for page break logic as MKay noted above. Again, similar to:

do while (main nodes)
i=1;
do while (inner nodes)
... stuff...
i++
end
end

Summary: I need to count across all the nodes (1-180 ... not 1-174, 1-3, 1-3) but need to restart counter.

Thanks again.
Rob
 
Old May 21st, 2010, 03:44 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

No sorry, that doesn't help at all. Can you actually post an example output XML, based on a sample input XML (preferably not one with 180 elements in it).

Have you tried using <xsl:number/>?
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
 
Old May 21st, 2010, 05:08 PM
Authorized User
 
Join Date: May 2010
Posts: 16
Thanks: 0
Thanked 0 Times in 0 Posts
Default

**
Fair enough. I have linked my updated page below. I'm now using a more reasonable number of nodes but still enough to see some sort of page break logic. Please note that at the TOP of the page there are links for my sample XML and XSL.

http://share.rjfweb.com/XML/ProcessP...MySample_1.xml

Also, instead of Main, Sub1, Sub2... please see
<Confirm>
<Collaterals>
<Collateral>
<CollateralDtl>
There are two global variables at the top of stylesheet:
<xsl:variable name="itemsFirstPage" select="9"/>
<xsl:variable name="itemsPerPage" select="12"/>

Kind of self-explanatory - i.e. how many nodes to appear on first page, how many to appear on remaining pages.

In the example you will see that there should be 3 pages (which is correct) but only two exist since the count is off.

Hope someone can lend a little guidance.
Thanks.
Rob

Last edited by rfossella; May 24th, 2010 at 04:14 AM..





Similar Threads
Thread Thread Starter Forum Replies Last Post
hit counter alfredogirosi ASP.NET 3.5 Basics 1 April 14th, 2009 08:18 AM
A Hit Counter, PLEASE HELP !!!!! ARD_40 BOOK: Beginning PHP4/PHP 5 ISBN: 978-0-7645-4364-7; v5 ISBN: 978-0-7645-5783-5 1 April 23rd, 2006 06:25 AM
Counter tp194 Javascript 1 September 2nd, 2004 08:02 AM
the counter is not incremented harag XSLT 2 November 10th, 2003 11:54 AM
counter Adam H-W Classic ASP Basics 15 August 15th, 2003 11:18 AM





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