Bonjour!

My last example seemed to cause some misunderstandings, so I worked on a better one. Here it comes:


I have an XML file with the names of players.

<?xml version="1.0" encoding="UTF-8"?>
<doc>
	<data number="1" type="x">herbert</data>
	<data number="2">joe</data>
	<data number="3">jean-jacques</data>
</doc>


With the following XSLT file I want to initialize each player with a random numeric value und send it to the output. The last line should contain the sum of all initial values.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <xsl:variable name="seed" select="2"/>
    <html>
      <body>
        <table border="1">
          <tr>
            <th>Name</th>
            <th>Inital Value</th>
          </tr>
          <xsl:for-each select="/doc/data">
          <tr>
            <td>
              <xsl:value-of select="."/>
            </td>
            <td><!-- this is a (very poor) pseudo-random function. think of it as a real random function -->
              <xsl:value-of select="substring(substring-after($seed div (position()*string-length     ()), '.'),2, 3)"/>              
            </td>
          </tr>
         </xsl:for-each>
         <tr>
           <td>sum</td>
            [color=red]<td>????</td> > <!-- how do i calculate the sum ? -->[/color]
         </tr>
       </table>
     </body>
  </html>
</xsl:template>
<xsl:template match="*|@*|text()">
</xsl:template>
</xsl:stylesheet>



The output should look like this

<html>
<body>
<table border="1">
  <tr><td>herbert</td><td>857</td></tr>
  <tr><td>joe</td><td>333</td></tr>
  <tr><td>jean-jacques</td><td>555</td></tr>
  <tr><td>Sum</td><td>1745</td></tr>
</table>
</body>
</html>


How can I calculate the sum of the random numbers

Thanks for help

Tschuri
Edited by Tschuri (08 May 2005 - 11:08)
I don't known if you didn't read my answer to your last topic or if you were not happy with it, but sure it is a right one that match also your new example. So here again is my proposition :

From a theorical point of view and considering the way variables work in XSLT, the normal way to do a calculation (like a sum) with numbers that are indexed by elements of an XML file is to use the main and natural characteristic of a template : recursivity.
This means :
- write a template that calls itself
- give a parameter while calling
- do whatever calculation with this parameter (an addition will fit your need).
Thanks for the advice.

Of course I thought of recursion as well and I tried it with recursive call-template calls and apply-template calls.
I managed easily to substitute the for-each loop by recursion but the problem was, but the problem is that the for-each loop produces only the table-rows with the initial values for each player.
I couldn't find a way to store the sum of the values and output it ONLY at the last table row.
There are many ways to do it. For example :
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="seed" select="2"/>
<xsl:param name="nb" select="count(//data)"/>
<xsl:template match="/">
<html><body><table border="1">
<tr><th>Name</th><th>Inital Value</th></tr>
<xsl:apply-templates select="/doc/data[1]" >
	<xsl:with-param name="cumul" select="0"/>
	<xsl:with-param name="rang" select="1"/>
</xsl:apply-templates>
</table></body></html>
</xsl:template>

<xsl:template match="//data">
<xsl:param name="cumul"/>
<xsl:param name="rang"/>
<xsl:param name="random" select="substring(substring-after($seed div ($rang*string-length ()), '.'),2, 3)"/>
<tr><td><xsl:value-of select="."/></td><td><xsl:value-of select="$random"/></td></tr>
<xsl:choose>
	<xsl:when test="$rang=$nb">
		<tr><td>sum</td><td><xsl:value-of select="$cumul+$random"/></td></tr>
	</xsl:when>
	<xsl:otherwise>
		<xsl:apply-templates select="following-sibling::data[1]" >
			<xsl:with-param name="cumul" select="$cumul+$random"/>
			<xsl:with-param name="rang" select="$rang+1"/>
		</xsl:apply-templates>
	</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Thank you Xavier!

This solution is much more elegant and conciser than the one I figured out.

In this case it works fine. But it still doesn't remove my sceptic attitude towards XSLT, since the problem of accumulating values in a loop is not really a problem in any traditional language, while in XSLT the problem solution is non trivial (at least for me).

I know that XSLT is intentionally designed to dispense with variables in order to avoid unwanted side effects. What I really don't understand is, why xsl:variables are called variables as the nature of variables in other languages is that their values are allowed to vary and change which distinguishes them from constants which have a fixed value.

Your solution, though perfectly solving the given problem, has one disadvantage anyway. What if there were real random numbers available in XSLT (not only pseudo random)?
Than it would not be possible to calculate the random numbers once again like you did in your function, after they were calculated the first time inside the loop.
This is also a performance issue, since even calculating a good pseudo random number consumes non-neglectable processor time. In your example it has to be done twice.
Of course my question about real random numbers is a bit hypothetic as, according to my knowledge, there is no way in XSLT to produce them programmatically, but only by an input file that contains them. And in this case you could access them after the loop by an XPATH expression to calculate the sum.


Real variables were really a nice thing in XSLT as the penalty of making trivial problems complicated is a price too high to pay in order to avoid side effects by changing values of variables. But this is more of a philosophical question and I bet Michael Kay 's arguments about constant variables might beat my arguments against them.

Tschuri
Tschuri a écrit :
Your solution, though perfectly solving the given problem, has one disadvantage anyway. What if there were real random numbers available in XSLT (not only pseudo random)?
Than it would not be possible to calculate the random numbers once again like you did in your function, after they were calculated the first time inside the loop.
This is also a performance issue, since even calculating a good pseudo random number consumes non-neglectable processor time. In your example it has to be done twice.
I am afraid you misunderstood the code. The random calculation is done only once. Then it works with a real random function if you have one.
Tschuri a écrit :
Of course my question about real random numbers is a bit hypothetic as, according to my knowledge, there is no way in XSLT to produce them programmatically, but only by an input file that contains them. And in this case you could access them after the loop by an XPATH expression to calculate the sum.
Sorry but it is wrong again. XSLT was not design to be a functional programming language, but in fact it has "by hazard" this property. The existence of namespaces (introduce with XML) leads XSLT to be, in an non obvious mechanism, a real functional programming language. Then it is possible to program any kind of mathematical function.
Tschuri a écrit :
But it still doesn't remove my sceptic attitude towards XSLT, since the problem of accumulating values in a loop is not really a problem in any traditional language, while in XSLT the problem solution is non trivial (at least for me)
Well it is up to you. On my side I am happy with XSLT which gave my the possibility to do things I won't be able to do easily with other languages.

In fact it is a very specific language that need a specific state of mind to be deeply understood. Then it is not easy to use for someone who wants to think the same way as he thinks with common procedural languages. Despite this wrong side, it is very powerfull, and if your are not afraid, you will discover than loop or variables that vary are not so usefull. One main thing with XSLT is recursivity. But it is right that brain is quickly lost with recursivity.
Tschuri a écrit :
This solution is much more elegant and conciser
Well it is possible to do better as the <xsl:param name="rang"/> is not necessary (just here to make the example clearer if possible)
Hello Xavier!

You are right. When I first had a look at your code I thought you meant the template to be added to my template. But on the second sight I realized that it does the whole job.
So in that case of course it works with real randoms.

Maybe I have to get deeper into XSLT to see its real value.

Tschuri