Skip to content

Instantly share code, notes, and snippets.

@xpathr
Created May 10, 2012 14:41
Show Gist options
  • Select an option

  • Save xpathr/2653546 to your computer and use it in GitHub Desktop.

Select an option

Save xpathr/2653546 to your computer and use it in GitHub Desktop.
Number To Words by nickdunn
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" xmlns:math="http://exslt.org/math" extension-element-prefixes="exsl math">
<!--
Name: Number To Words
Version: 1.0
Author: Nick Dunn <nick@nick-dunn.co.uk>
URL: http://symphony-cms.com/downloads/xslt/file/20486/
Parameters:
* number (required) an integer
* resolution (optional) round 'number' to the nearest 'resolution', e.g. '10', '50, '1000' etc. Use '-1' to allow the template to choose an appropriate rounding resolution
* minimum (optional) if the number is less than this the returned string will be 'less than $number'
* maximum (optional) if the number is more than this the returned string will be 'more than $number'
Further usage examples:
http://symphony-cms.com/forum/discussions/763/
-->
<xsl:template name="number-to-words">
<xsl:param name="number" />
<xsl:param name="resolution" />
<xsl:param name="minimum" />
<xsl:param name="maximum" />
<xsl:variable name="words">
<words>
<word integer="0">zero</word>
<word integer="1">one</word>
<word integer="2">two</word>
<word integer="3">three</word>
<word integer="4">four</word>
<word integer="5">five</word>
<word integer="6">six</word>
<word integer="7">seven</word>
<word integer="8">eight</word>
<word integer="9">nine</word>
<word integer="10">ten</word>
<word integer="11">eleven</word>
<word integer="12">twelve</word>
<word integer="13">thirteen</word>
<word integer="14">fourteen</word>
<word integer="15">fifteen</word>
<word integer="16">sixteen</word>
<word integer="17">seventeen</word>
<word integer="18">eighteen</word>
<word integer="19">nineteen</word>
<word integer="20">twenty</word>
<word integer="30">thirty</word>
<word integer="40">forty</word>
<word integer="50">fifty</word>
<word integer="60">sixty</word>
<word integer="70">seventy</word>
<word integer="80">eighty</word>
<word integer="90">ninety</word>
<word handle="hundred">hundred</word>
<word handle="thousand">thousand</word>
<word handle="million">million</word>
<word handle="less-than">less than</word>
<word handle="more-than">more than</word>
<word handle="about">about</word>
<word handle="and">and</word>
</words>
</xsl:variable>
<xsl:variable name="number-negative">
<xsl:value-of select="$number &lt; 0"/>
</xsl:variable>
<xsl:variable name="number">
<xsl:value-of select="math:abs(translate($number,',',''))"/>
</xsl:variable>
<xsl:if test="string(number($number)) != 'NaN'">
<xsl:variable name="resolved-number">
<xsl:variable name="auto-resolution">
<xsl:choose>
<xsl:when test="$resolution = -1">
<xsl:choose>
<xsl:when test="$number &lt; 20">
<xsl:text>1</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 100">
<xsl:text>5</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 500">
<xsl:text>10</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 1000">
<xsl:text>50</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 5000">
<xsl:text>100</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 25000">
<xsl:text>500</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 100000">
<xsl:text>1000</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 500000">
<xsl:text>5000</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 1000000">
<xsl:text>10000</xsl:text>
</xsl:when>
<xsl:when test="$number &lt; 5000000">
<xsl:text>100000</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>1000000</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$resolution"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$auto-resolution and $auto-resolution &lt;= $number">
<xsl:variable name="divided" select="$number div $auto-resolution"/>
<xsl:choose>
<xsl:when test="$divided - floor($divided) &gt;= 0.5">
<xsl:value-of select="ceiling($divided) * $auto-resolution"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="floor($divided) * $auto-resolution"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:text>0</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$number &lt; $minimum">
<xsl:value-of select="exsl:node-set($words)//word[@handle='less-than']"/>
<xsl:text> </xsl:text>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="$minimum" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$number &gt; $maximum">
<xsl:value-of select="exsl:node-set($words)//word[@handle='more-than']"/>
<xsl:text> </xsl:text>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="$maximum" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$resolved-number != 0">
<xsl:if test="$resolved-number != $number">
<xsl:value-of select="exsl:node-set($words)//word[@handle='about']"/>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:if test="$number-negative = 'true'">
<xsl:value-of select="exsl:node-set($words)//word[@handle='minus']"/>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="$resolved-number" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$number-negative = 'true'">
<xsl:value-of select="exsl:node-set($words)//word[@handle='minus']"/>
<xsl:text> </xsl:text>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="$number"/>
</xsl:call-template>
</xsl:if>
<xsl:choose>
<xsl:when test="$number &lt; 21">
<xsl:value-of select="exsl:node-set($words)//word[@integer = $number]"/>
</xsl:when>
<xsl:when test="$number &lt; 100">
<xsl:value-of select="exsl:node-set($words)//word[@integer = (10 * floor($number div 10))]"/>
<xsl:variable name="remainder" select="floor($number mod 10)"/>
<xsl:if test="$remainder &gt; 0">
<xsl:text>-</xsl:text>
<xsl:value-of select="exsl:node-set($words)//word[position() = ($remainder + 1)]"/>
</xsl:if>
</xsl:when>
<xsl:when test="$number &lt; 1000">
<xsl:value-of select="exsl:node-set($words)//word[@integer = (floor($number div 100))]"/>
<xsl:text> </xsl:text>
<xsl:value-of select="exsl:node-set($words)//word[@handle='hundred']"/>
<xsl:variable name="remainder" select="floor($number mod 100)"/>
<xsl:if test="$remainder &gt; 0">
<xsl:text> </xsl:text>
<xsl:value-of select="exsl:node-set($words)//word[@handle='and']"/>
<xsl:text> </xsl:text>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="$remainder"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:when test="$number &lt; 1000000">
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="floor($number div 1000)"/>
</xsl:call-template>
<xsl:text> </xsl:text>
<xsl:value-of select="exsl:node-set($words)//word[@handle='thousand']"/>
<xsl:variable name="remainder" select="floor($number mod 1000)"/>
<xsl:if test="$remainder &gt; 0">
<xsl:text>, </xsl:text>
<xsl:if test="$remainder &lt; 100">
<xsl:value-of select="exsl:node-set($words)//word[@handle='and']"/>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="$remainder"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="floor($number div 1000000)"/>
</xsl:call-template>
<xsl:text> </xsl:text>
<xsl:value-of select="exsl:node-set($words)//word[@handle='million']"/>
<xsl:variable name="remainder" select="floor($number mod 1000000)"/>
<xsl:if test="$remainder &gt; 0">
<xsl:text>, </xsl:text>
<xsl:if test="$remainder &lt; 100">
<xsl:value-of select="exsl:node-set($words)//word[@handle='and']"/>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:call-template name="number-to-words">
<xsl:with-param name="number" select="$remainder"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment