Re: [xsl] Math: Removing X number of zeroes from number Y.

Subject: Re: [xsl] Math: Removing X number of zeroes from number Y.
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Tue, 7 Jun 2005 07:05:02 +1000
On 6/7/05, Ahsan Ali <doubleletter@xxxxxxxxx> wrote:
> Hi,
>
> I have a fare element that is returned as, for example, 79000. The
> decimal point value is specified in another element as for example 2.
> Therefore the number should be: 790.00
>
> There's a way to do this mathematically:
>
> Where x=DecimalPoint, and y=fare, the forumla would be y/(10^x)
>
> But as far as I know there's no exponential function in XSLT 1.0. I'm
> using, or rather, _have_ to use MSXML, I can't go for FXSLT, etc.
>
> It's worth mentioning that fare is of type 'double' and DecimalPoint
> is of type 'short'
>
> Anyone have any ideas on how to do this in plain XSL ?

As a number of people have pointed out, this problem has a simple
solution using the substring() function.

This problem is a special case of a more general and very frequently
encountered task:
"Do something N times, every time using the result of the previous as input"

This can be implemented on every case by manually coding a recursive
template.

Or it can be implemented once and forever, and then simply reused.
This is the idea behind the "iter" template of FXSL.

To use it one doesn't need to have the FXSL library -- the "iter"
template has no dependencies on other FXSL templates.

Here's the code for MSXML:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:vendor="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="xsl vendor">

<!--
===========================================================================
       this implements functional power composition,
       that is f(f(...f(x)))))...)

       f composed with itself n - 1 times

       The corresponding Haskell code is:
        > iter :: (Ord a, Num a) => a -> (b -> b) -> b -> b
        > iter n f
        >    | n > 0     = f . iter (n-1) f
        >    | otherwise = id
===========================================================================--
>
<!--
    Template: iter
     Purpose: Iterate (compose a function with itself) N times
  Parameters:-
    $pTimes - [optional] number of times to iterate
    $pFun   - a template reference to the function that's to be iterated
    $pX     - an initial argument to the function
  ==========================================================================
-->
  <xsl:template name="iter">
    <xsl:param name="pTimes" select="0"/>
    <xsl:param name="pFun" select="/.."/>
    <xsl:param name="pX" />

    <xsl:choose>
      <xsl:when test="$pTimes = 0" >
        <xsl:copy-of select="$pX"/>
      </xsl:when>
      <xsl:when test="$pTimes = 1">
        <xsl:apply-templates select="$pFun">
          <xsl:with-param name="arg1" select="$pX"/>
          </xsl:apply-templates>
      </xsl:when>
      <xsl:when test="$pTimes > 1">
        <xsl:variable name="vHalfTimes" select="floor($pTimes div 2)"/>
        <xsl:variable name="vHalfIters">
          <xsl:call-template name="iter">
            <xsl:with-param name="pTimes" select="$vHalfTimes"/>
	<xsl:with-param name="pFun" select="$pFun"/>
	<xsl:with-param name="pX" select="$pX"/>
          </xsl:call-template>
        </xsl:variable>

        <xsl:call-template name="iter">
          <xsl:with-param name="pTimes" select="$pTimes - $vHalfTimes"/>
	<xsl:with-param name="pFun" select="$pFun"/>
	<xsl:with-param name="pX" select="vendor:node-set($vHalfIters)"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message>[iter]Error: the $pTimes argument must be
                      a positive integer or 0.
        </xsl:message>
      </xsl:otherwise>
    </xsl:choose>

  </xsl:template>


And here's an example how to use the iter template. This multiplies by
3 N times, where N = 4, and the result is, as expected, 81


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:myMultiplyby3="f:myMultiplyby3"
 exclude-result-prefixes="xsl myMultiplyby3">

 <xsl:import href="iter.xsl"/>

 <xsl:output omit-xml-declaration="yes"/>

  <myMultiplyby3:myMultiplyby3/>

  <xsl:template match="/">

   <xsl:variable name="vMultBy3" select="document('')/*/myMultiplyby3:*[1]"/>

    <xsl:call-template name="iter">
      <xsl:with-param name="pTimes" select="4"/>
      <xsl:with-param name="pFun" select="$vMultBy3"/>
      <xsl:with-param name="pX" select="1"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="myMultiplyby3:*">
    <xsl:param name="arg1"/>

    <xsl:value-of select="3 * $arg1"/>
  </xsl:template>

</xsl:stylesheet>


Cheers,
Dimitre Novatchev.

Current Thread