Increment and check counter variable in XSLT

It's not easy for me to assign a counter variable and increment it, and then check for a specific value in XSLT. Here is my code:

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" <xsl:variable name="empty_string"/> <xsl:variable name="counter" select="0"/> <xsl:template match="/Collection"> <xsl:for-each select="Content"> <xsl:sort select="Html/root/Event/start_date" order="ascending"/> <xsl:variable name="isFutureEvent"> <xsl:value-of select="syscom:isFutureDate(Html/root/Event/start_date)" /> </xsl:variable> <xsl:if test="Html/root/Event != $empty_string"> <xsl:if test="$isFutureEvent='true'"> <!-- Increment Counter --> <xsl:value-of select="$counter + 1"/> <!-- Test if Counter < 4 --> <xsl:if test="$counter &lt; 3"> <div class="media"> <!-- Do stuff here --> </div> </xsl:if> <!-- End if for counter --> </xsl:if> </xsl:if> <!--</xsl:when>--> <!--</xsl:choose>--> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

But it does not seem to increment the counter and does not exit when the counter is accessed 3. Any help on this?

+6
source share
6 answers

XSL "variables" are actually constants - you cannot change their value. It:

 <xsl:value-of select="$counter + 1"/> 

just print the value of $counter+1

To execute loops you need to use recursion - for example:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template name="loop"> <xsl:param name="i"/> <xsl:param name="limit"/> <xsl:if test="$i &lt;= $limit"> <div> <xsl:value-of select="$i"/> </div> <xsl:call-template name="loop"> <xsl:with-param name="i" select="$i+1"/> <xsl:with-param name="limit" select="$limit"/> </xsl:call-template> </xsl:if> </xsl:template> <xsl:template match="/"> <html> <body> <xsl:call-template name="loop"> <xsl:with-param name="i" select="0"/> <xsl:with-param name="limit" select="10"/> </xsl:call-template> </body> </html> </xsl:template> </xsl:stylesheet> 

although it’s better to try to avoid loops - in most cases, XSL can be written to avoid this, but I don’t understand what you are trying to achieve to give you a complete solution.

+11
source

I have the same problem. I need an increment value in a loop. Thus, the easiest way is to enable Saxon and use this value.

if you are using Saxon 6.5.5

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ... xmlns:saxon="http://icl.com/saxon" extension-element-prefixes="saxon" version="3.0"> 

if you are using Saxon 9.4.0.4

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ... xmlns:saxon="http://saxon.sf.net/" extension-element-prefixes="saxon" version="3.0"> 

And after that you can just use the saxon variable:

 <xsl:variable name="counter" select="0" saxon:assignable="yes"/> <!-- declare value --> <saxon:assign name="counter" select="$counter+1"/> <!-- increment value, you can do it in loop for example--> <xsl:value-of select="$counter"></xsl:value-of> <!-- print value --> 
+7
source

If someone wants to do this using .net ( XslCompiledTransform ), you can use

 <xsl:stylesheet ... xmlns:customCode="urn:customCode"> <msxsl:script language="VB" implements-prefix="customCode"> <![CDATA[ private mCounter As Integer Public Function AddToCounter() As Boolean mCounter += 1 Return True End Function Public Function GetCounter() As Integer Return mCounter End Function ]]> </msxsl:script> 

Then you add a call to "customCode: AddToCounter ()" and then you can write a message like this <xsl:message><xsl:value-of select="customCode:GetCounter()" /> rows remaining.</xsl:message>

+2
source

We cannot update xsl:variable , since they look like constants. But we can update dp:local-variables , so here dp:local-variable counter is initialized before running for-loop. Each cycle of the cycle will be updated to 1. Try the following:

 <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" <xsl:variable name="empty_string"/> <xsl:template match="/Collection"> <dp:set-local-variable name="'counter'" value="0"/> <xsl:for-each select="Content"> <dp:set-local-variable name="'counter'" value="dp:local-variable('counter')+1"/> <xsl:sort select="Html/root/Event/start_date" order="ascending"/> <xsl:variable name="isFutureEvent"> <xsl:value-of select="syscom:isFutureDate(Html/root/Event/start_date)" /> </xsl:variable> <xsl:if test="Html/root/Event != $empty_string"> <xsl:if test="$isFutureEvent='true'"> <xsl:value-of select="dp:local-variable('counter')"/> <!-- Test if Counter < 4 --> <xsl:if test="dp:local-variable('counter') &lt; 3"> <div class="media"> <!-- Do stuff here --> </div> </xsl:if> <!-- End if for counter --> </xsl:if> </xsl:if> <!--</xsl:when>--> <!--</xsl:choose>--> </xsl:for-each> </xsl:template> </xsl:stylesheet> 
+1
source

If you want to know where you are in the for-each loop, you can use the built-in position () function.

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/Collection"> <xsl:for-each select="Content"> <xsl:if test="position() &lt; 3"> <!-- Do this for nodes 1, 2 and 3 --> </xsl:if> <!-- Do this for every node --> </xsl:for-each> </xsl:template> </xsl:stylesheet> 
0
source

In my case, I needed all the boxes in the party, it helped

  <xsl:for-each select="ShippingConfirmation/Details/LicensePlates/LicensePlate"> <xsl:if test="position()=last()"> <xsl:value-of select="position()"/> </xsl:if> </xsl:for-each> 
0
source

Source: https://habr.com/ru/post/910201/


All Articles