tags:

views:

133

answers:

4

I have the code below. I would the for-each to stop running after the if-sentenses have returned true and executed the code block 4 times. As i have no idea when the code block has been executed 4 times i can't use position() which was my first idea.

Any help would be greatly appreciated.

<xsl:for-each select="$itm//item[@template='news item']">
    <xsl:sort select="sc:fld('start date',.)" data-type="text" order="descending"/>
    <xsl:if test="sc:formatdate($date,'yyyyMMddHHmm') &gt; sc:formatdate(sc:fld('start date',.),'yyyyMMddHHmm')">
        <xsl:if test="sc:formatdate($date,'yyyyMMddHHmm') &lt; sc:formatdate(sc:fld('end date',.),'yyyyMMddHHmm')">
    <!--EXECUTE A CODE BLOCK-->
        </xsl:if>
    </xsl:if>
</xsl:for-each>
A: 

No because xslt is not a procedural language, the statement is so to speak running in a parallel way, getting all the data simultaneously and then displaying it. so it has no knowledge of iteration.

PurplePilot
Not very constructive.
Obalix
A: 

Well you cannot "exit" a for loop in xlst (see link). So you will have to to at it in a different way:

  1. Alter the select statement so that for-each only iterates over the four items for which you want to execute your code.
  2. Use recursion (using call-template or apply-template and a parameter passsed into the template with with-param). On each recursion you can increment the parameter if the code block was executed prior to passing it to the next recursion level. You have to check whether the parameter is equal to 4 before you are entering the next recursion level (i.e. the exit condition for the recursive function).

    <!-- exit condition -->
    <xsl:if test="$executed &lt; 4">
        <!-- check conditions and select next item -->
        <xsl:choose>
            <!-- condition for items where the code should be executed -->
            <xsl:when test="test whether code should be executed">
                <!-- execute your code here -->
                <xsl:apply-templates select="select next item" mode="recursive">
                    <xsl:with-param name="executed" select="$executed + 1"/>
                </xsl:apply-templates>
            </xsl:when>
            <!-- condition for items where the code should not be executed -->
            <xsl:otherwise>
                <xsl:apply-templates select="select next item" mode="recursive">
                    <xsl:with-param name="executed" select="$executed"/>
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
    

Obalix
But as far as i know neither of those options gives me the ability to sort the items i the xml, correct me if i'm wrong?
Hans Skov
Maybe this might help you further http://stackoverflow.com/questions/1643621/xsl-recursive-sort/1645790. Although, I can see that it might complicate things. So I fear that there is no easy solution. Generally, it can be said that if you need looping with a break you will have to use recursion in one way or another. You can also look at http://www.dpawson.co.uk/xsl/sect2/sect21.html to see if there is any more on your specific problem.
Obalix
+1  A: 
<!-- convenience variables -->
<xsl:variable name="dtFormat" select="'yyyyMMddHHmm'" />
<xsl:variable name="theDate" select="sc:formatdate($date, $dtFormat)" />

<!-- don't loop over nodes testing a condition on each one separately, 
     just select the interesting ones directly -->
<xsl:variable name="MatchingFields" select="
  $itm//item[@template='news item'][
    sc:formatdate(sc:fld('start date', .), $dtFormat) &lt; $theDate
    and
    sc:formatdate(sc:fld('end date', .), $dtFormat) &gt; $theDate
  ]
" />

<!-- now do something with the nodes -->
<xsl:for-each select="$MatchingFields">
  <xsl:sort select="sc:fld('start date',.)" data-type="text" order="descending"/>
  <!--EXECUTE A CODE BLOCK-->
</xsl:for-each>

<!-- you can also count them (this is your "hit counter") -->
<xsl:value-of select="count($MatchingFields)" />
Tomalak
that did the trick, thanks
Hans Skov
A: 

Can't you put the conditions in a predicate of the select expression and the use position in the for-each, as follows:

<xsl:for-each select="$itm//item[@template='news item'][sc:formatdate($date,'yyyyMMddHHmm') &gt; sc:formatdate(sc:fld('start date',.),'yyyyMMddHHmm')][sc:formatdate($date,'yyyyMMddHHmm') &lt; sc:formatdate(sc:fld('end date',.),'yyyyMMddHHmm')]">
    <xsl:sort select="sc:fld('start date',.)" data-type="text" order="descending"/>
    <xsl:if test="position() &lt; 5">
      <!-- output something -->
    </xsl:if>
</xsl:for-each>
Martin Honnen