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.
damianbekAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkmyoungCommented:
To do this easily, either write an extension function or use a parser dependent function.
eg. if you're using saxon:  
<xsl:variable name="counter0" select="0" saxon:assignable="yes"/>
and
<saxon:assign name="counter0" select="$counter0 + 1"/>

or if you want to use an extension function, call a static function, or something that uses a static variable. not sure how much you already know about that.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jkmyoungCommented:
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...
0
damianbekAuthor Commented:
They are a more simpler method, like define variables, or insert javascript code in XSL??
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

MogalManicCommented:
This should work
...
<xsl:for-each select="Component/item">
    <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0">
        <xsl:variable name='itemPos' select='position()'/>
        <TR>
            <TD onclick="showMovieTags()" style="cursor:hand">
                <SPAN class="openTag"><![CDATA[<]]></SPAN>
                <SPAN class="tagName">item</SPAN>
                <SPAN class="openTag">></SPAN>
            </TD>
            <TD>
                <xsl:variable select='$itemPos'/>
            </TD>
        </TR>
        <xsl:for-each select="sub_item">
            <xsl:variable name='subPos' select='position()'/>
            <TR id="tagTR" name="tagTR" style="display:block">
                <TD>
                    <xsl:value-of select="."/>
                </TD>
            </TR>
        </xsl:for-each>
    </TABLE>
</xsl:for-each>
...
0
rdcproCommented:
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

0
rdcproCommented:
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
0
jkmyoungCommented:
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.
0
J_MakCommented:
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.
0
rdcproCommented:
There are other optimizations that can occur.  For example, the XSLT processor is not required to execute a template that does not produce output.  This can be determined when the XSLT is compiled, so you'd find that the template isn't even *in* the compiled XSLT.  

And there's no guarantee that successive versions of the same processor won't suddenly break an extension function that is not a pure function.  There's no reason that I can think of to use xsl:script extensions that are not pure functions (ie: have no side-effects):

http://www.biglist.com/lists/xsl-list/archives/200102/msg00903.html

But, in any case, it looks to me like the poster is trying to use counters to build a table with an arbitrary number of cells (or some similar purpose).  Going down this path leads one to do silly things like:

BadExample.xslt:
=====================================
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxsl="urn:schemas-microsoft-com:xslt"
      xmlns:bad="urn:rdcpro-com:worstpractice"
      exclude-result-prefixes="bad msxsl">
      <xsl:output method="xml" encoding="UTF-8"/>
      <msxsl:script language="JScript" implements-prefix="bad"><![CDATA[  
            var iCounter
            iCounter = 0
            function getCounter()
            {
                  return parseInt(iCounter)
            }
            function incrementCounter()
            {
                  iCounter++
                  return true
            }
                  
      ]]></msxsl:script>
      <xsl:template match="root">
            <table>
                  <tr>
                        <xsl:for-each select="myNode">
                              <xsl:if test="bad:incrementCounter()">
                                    <td>
                                          <xsl:value-of select="."/>
                                    </td>
                              </xsl:if>
                              <xsl:if test="bad:getCounter() mod 4 = 0">
                                    <xsl:text disable-output-escaping="yes">
                                        &lt;/tr&gt;
                                        &lt;tr&gt;
                                    </xsl:text>
                              </xsl:if>
                        </xsl:for-each>
                  </tr>
            </table>
      </xsl:template>
</xsl:stylesheet>


instead of constructing a table the right way.  It's possible to build the table using recursive templates and safe counters, but even that isn't necessary.  

Regards,
Mike Sharp  
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.