XSL Loop inside a template

www picture www · Nov 2, 2012 · Viewed 7.6k times · Source

I am trying to create a loop inside a template. I found 2 methods, but both of them did not work:

Method 1:

<xsl:template name="recurse_till_ten">
    <xsl:param name="num">1</xsl:param> <!-- param has initial value of
1 -->
    <xsl:if test="not($num = 10)">
        ...do something
        <xsl:call-template name="recurse_till_ten">
            <xsl:with-param name="num">
                <xsl:value-of select="$num + 1">
            </xsl:with-param>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

Method 2:

<xsl:variable name="count" select="'5'"/> 
<xsl:for-eachselect="(//*)[position()&lt;=$count]"> 
 <!-- Repeated content Here --> 
 <!-- use position() to get loop index --> 
 <xsl:value-of select="position()"/>.<br/> 
</xsl:for-each>

Method 1 gave the following error:

element template only allowed as child of stylesheet

Method 2 did not show anything since I am using another position() for displaying some outputs:

<td>
        <xsl:if test='buildid = /cdash/etests/etest/buildid'>
                            <xsl:variable name='index' 
                                          select='2*count(preceding-sibling::build[buildid = /cdash/etests/etest/buildid])+position()' />
                            <xsl:value-of select="/cdash/etests/etest[position()=$index]/value" />
        </xsl:if>
                        </td>

How can I create a loop that should call the code between two times?

Original XSL:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>

<xsl:include href="header.xsl"/>
<xsl:include href="footer.xsl"/>

<xsl:include href="local/header.xsl"/>
<xsl:include href="local/footer.xsl"/>

<xsl:output method="xml" indent="yes"  doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
   doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" />
<xsl:template match="/">
<html>
<head>
  <title><xsl:value-of select="cdash/title"/></title>
  <meta name="robots" content="noindex,nofollow" />
  <link rel="StyleSheet" type="text/css">
    <xsl:attribute name="href">
      <xsl:value-of select="cdash/cssfile"/>
    </xsl:attribute>
  </link>
  <xsl:call-template name="headscripts"/>
   <!-- Include JavaScript -->
  <script src="javascript/cdashTestGraph.js" type="text/javascript" charset="utf-8"></script>

</head>
<body bgcolor="#ffffff">

<xsl:choose>
<xsl:when test="/cdash/uselocaldirectory=1">
  <xsl:call-template name="header_local"/>
</xsl:when>
<xsl:otherwise>
  <xsl:call-template name="header"/>
</xsl:otherwise>
</xsl:choose>

<br/>
<h3>Testing summary for
<u><xsl:value-of select="cdash/testName"/></u>
 performed between <xsl:value-of select="cdash/builds/teststarttime"/> and <xsl:value-of select="cdash/builds/testendtime"/>
</h3>

<!-- Failure Graph -->
<a>
<xsl:attribute name="href">javascript:showtestfailuregraph_click('<xsl:value-of select="/cdash/dashboard/projectid"/>','<xsl:value-of select="/cdash/testName"/>','<xsl:value-of select="/cdash/builds/currentstarttime"/>')</xsl:attribute>
Show Test Failure Trend
</a>
<div id="testfailuregraphoptions"></div>
<div id="testfailuregraph"></div>
<center>
<div id="testfailuregrapholder"></div>
</center>
<br/>
<!-- Test Summary table count(preceding-sibling::etests[columnname]) + 1 count(/cdash/etests/columnname) + 1  /cdash/etests/columnname[position()=$index] -->
<table id="testSummaryTable" cellspacing="0" cellpadding="3" class="tabb">
<thead>
  <tr class="table-heading1">
    <th id="sort_0">Site</th>
    <th id="sort_1">Build Name</th>
    <th id="sort_2">Build Stamp</th>
    <th id="sort_3">Status</th>
    <th id="sort_4">Time (s)</th>
    <th id="sort_5">Build Revision</th>
    <xsl:for-each select='/cdash/etests/columnname'>
        <xsl:variable name='index_col' select='count(preceding-sibling::columnname) + 1'/>
        <th><xsl:attribute name="id">
            <xsl:value-of select="$index_col" />
        </xsl:attribute>
        <xsl:value-of select="/cdash/etests/columnname[position()=$index_col]" /></th>
    </xsl:for-each>



  </tr>
</thead>

<xsl:for-each select="cdash/builds/build">
  <tr>
    <td>
      <xsl:value-of select="site"/>
    </td>

    <td><a>
      <xsl:attribute name="href">
        <xsl:value-of select="buildLink"/>
      </xsl:attribute>
      <xsl:value-of select="buildName"/>
    </a></td>
    <td>
      <xsl:value-of select="buildStamp"/>
    </td>
    <td>
      <xsl:attribute name="class">
        <xsl:value-of select="statusclass"/>
      </xsl:attribute>
      <a>
      <xsl:attribute name="href">
        <xsl:value-of select="testLink"/>
      </xsl:attribute>
      <xsl:value-of select="status"/>
      </a>
    </td>
    <td>
      <xsl:value-of select="time"/>
    </td>
    <td>
      <a><xsl:attribute name="href"><xsl:value-of select="update/revisionurl"/></xsl:attribute>
         <xsl:value-of select="update/revision"/>
      </a>
    </td> 
    <!-- NEW ADDITIONNN !!!!!!!!!!! -->

        <td>
        <xsl:if test='buildid = /cdash/etests/etest/buildid'>
                            <xsl:variable name='index' 
                                          select='2*count(preceding-sibling::build[buildid = /cdash/etests/etest/buildid])+1' />
                            <xsl:value-of select="/cdash/etests/etest[position()=$index]/value" />
        </xsl:if>
                        </td>

        <td>
        <xsl:if test='buildid = /cdash/etests/etest/buildid'>
                            <xsl:variable name='index' 
                                          select='2*count(preceding-sibling::build[buildid = /cdash/etests/etest/buildid])+2' />
                            <xsl:value-of select="/cdash/etests/etest[position()=$index]/value" />
        </xsl:if>
                        </td>

    <!-- NEW ADDITIONNN !!!!!!!!!!! -->
  </tr>
</xsl:for-each>
</table>
<br/>

<!-- FOOTER -->
<br/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Original XML:

<?xml version="1.0" encoding="utf-8"?><cdash><title>Title</title><cssfile>cdash.css</cssfile><version>2.1.0</version><dashboard>
  <nextdate>2012-09-18</nextdate>
  </menu><etests>
<columnname>LoadTime</columnname>
<etest>
<name>LoadTime</name><buildid>19390</buildid><value>1777</value>
</etest>
<columnname>Median</columnname>
<etest>
<name>Median</name><buildid>19390</buildid><value>1508</value>
</etest>
<etest>
<name>LoadTime</name><buildid>19389</buildid><value>676</value>
</etest>
<etest>
<name>Median</name><buildid>19389</buildid><value>868</value>
</etest>
</etests>
<builds>
<projectid>1</projectid><currentstarttime>1347825600</currentstarttime><teststarttime>2012-09-16T22:00:00</teststarttime><testendtime>2012-09-17T22:00:00</testendtime>
<build>
<buildName>Linux</buildName><buildStamp>20120916-2100-Nightly</buildStamp><time>174.86</time><buildid>19390</buildid><buildLink>viewTest.php?buildid=19390</buildLink><testLink>testDetails.php?test=289784&amp;build=19390</testLink><status>Passed</status><statusclass>normal</statusclass></build>
<build>
<buildName>Linux</buildName><buildStamp>20120916-2100-Nightly</buildStamp><time>174.86</time><buildid>19389</buildid><buildLink>viewTest.php?buildid=19389</buildLink><testLink>testDetails.php?test=289784&amp;build=19389</testLink><status>Passed</status><statusclass>normal</statusclass></build>
</builds>
<generationtime>0.201</generationtime></cdash></xml>

Answer

Matthew Green picture Matthew Green · Nov 2, 2012

I'm not sure what you are trying to do in your method 2 process so I'm going to focus on the first one.

You will want to update the code to something like this

<xsl:template name="recurse_till_ten">
    <xsl:param name="num" />
    <xsl:if test="not($num = 10)">
        ...do something
        <xsl:call-template name="recurse_till_ten">
            <xsl:with-param name="num" select="$num + 1" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>

The only important change I made was not setting the variable in the loop. By setting it in the loop then you are always setting num = 1 which would make for an infinite loop.

So then you would call it somewhere else in your template by doing this.

<xsl:call-template name="recurse_till_ten">
    <xsl:with-param name="num" select="number('1')" />
</xsl:call-template>

That should allow you to loop until the variable hits 10.