Link to home
Start Free TrialLog in
Avatar of damianbek
damianbek

asked on

Insert a counter in XSL

Hi, i must insert ,a counter in a for-each xsl function.
This is part of the code:
counter0 = 0
counter1 = 0
<xsl:for-each select="Component/item">
<TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0">
<TR>
      <TD onclick="showMovieTags()" style="cursor:hand"><SPAN class="openTag"><![CDATA[<]]></SPAN><SPAN class="tagName">item</SPAN><SPAN class="openTag">></SPAN></TD>
      <TD>
counter0++

 </TD>
</TR>
<xsl:for-each select="sub_item">
<TR id="tagTR" name="tagTR" style="display:block">
      <TD>
      <xsl:value-of select="."/>
      </TD>
counter1++      
</TR>
.......

Is very urgent...
Thank you.
ASKER CERTIFIED SOLUTION
Avatar of jkmyoung
jkmyoung

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jkmyoung
jkmyoung

If you simply want a final count of all of them use the count function!!!
eg. select="count(Component/item)"
select="count(Component/item/sub_item)"

However, if you want to keep track of each, and those other 2 ways are not options, you could always do it using xpath: the count and position functions with conditions.
eg partial pseudocode:
<xsl:for-each select="Component">
<xsl:variable name="pos1" select="position()"/>
<xsl:for-each select="item">
<xsl:variable name="pos2" select="position()"/>

counter0: select="count(../../Component[position() &lt; $pos1]/item) + count(../item[position() &lt; $pos2])"

<xsl:for-each select="sub_item">
<xsl:variable name="pos3" select="position()"/>

counter1: select="count(../../../Component[position() &lt; $pos1]/item/sub_item)
                         + count(../../item[position() &lt; $pos2]/sub_item)
                         + count(../sub_item[position() &lt; $pos3])"
...
This won't be fast though...
Avatar of damianbek

ASKER

They are a more simpler method, like define variables, or insert javascript code in XSL??
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
A couple comments:

it's not necessary to write extensions or parser dependant functions--a counter is easily created with recursive template:

http://rdcpro.com/Members/rdcpro/snippets/recursionandcounting/

If you do use an extension function to implement a counter, remember that it is very dangerous to set global variables.  You cannot count on the order of execution of your templates.  XSLT is supposed to be a side-effects-free programming language, but using extensions makes it possible to code them anyway.  That doesn't mean you should! ;^)   Remember, XSLT variables are immutable for a reason.  Don't create scripting-based variables within XSLT just to get around that fact--it's only going to get you in trouble.

Using position() works only if the count you want relates to the nodeset, and if the nodeset contains only the nodes you're counting.  That said, its almost always better to do it that way, if you can.  In other words, do the filtering of the nodes in the apply-templates or for-each, not by conditionals in the target template.  This way it's a lot easier to do things like alternate table row background colors etc.

Judging by the poster's example, I would say you're trying to use counters in the wrong way.  XSLT is a lot different than most programming languages--it's declarative, not procedural.  There's probably a much better way of accomplishing the poster's real goal.

Regards,
Mike Sharp

Oh, I wanted to add that count() can be improved by the use of xsl:key to index the nodes you want to count.  This provides a much faster response when you have to do a lot of calculating on nodesets, say perhaps in some sort of report.
ex:  
<xsl:key name="myKey" match="myNode" use="filterConditionNode"/>
[...]
<xsl:value-of select="count(key('myKey', filterCondition)[additionalFilterCondition])"/>

This way the processor doesn't have to keep processing the entire nodeset for each calculation.

Regards,
Mike Sharp
Looking back I'm a little unsure what you want on the counter1, is there a seperate table data cell for it? eg:
<TD>
counter1++
</TD>
really, xslt isn't designed to use counters. I'm guessing you're using the browser xslt processor, which means the saxon:assign function is out (although it is cheating somewhat anyways).

???? don't understand how that recursive counter applies in this case.

'insert javascript code in XSL': as noted before, the order of processing is supposed to be independent, but since most computers don't have multi-processors as of yet, IE processing is linear and probably will be for awhile at least. Dangerous, but works for now. calling a global function seems to be your best bet, given what you've told us you know so far.

I suppose you could speed up the count/position method by using keys, or even a secondary variable(s); but this is definitely more complicated.
I agree with rdcpro. You should use recursive templates. It is the safest way to update and change a variable, which is usually passed as a parameter.

CHeers.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial