Click here to Skip to main content
15,883,854 members
Articles / Web Development / HTML

XSLT Number to String Transformation

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
6 Jul 2008CPOL3 min read 39.1K   229   12  
An XSLT transform for string representation of numeric place values
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="html" indent="yes" />

  <!-- 
       Conversion Algorithm
       ===================
       
       1. Read each number in XML and check if it contains a hundred place value.
       If yes insert a '0' character at 4th place in string from right position.
       (This step handles the exception since only a hunderd place value is evaluated 
       as a single digit in Indian place-value number system rest all places have 
       paired values.)       
       (1234 -> 10234)
       
       2. Check if string have odd number of characters after Step 1.
       If yes prefix string with a '0' character.
       (This step make sure that string contains even number of character thus string
       will be splitted into digit pairs later on and translated to its string equivalent.)       
       (10234->010234)
       
       3. Foreach pair call translator with the pair value and its position in string.
       position is determined by dividing length of string by 2.
       value:01 place:3 evaluates to 'One Thousand'
       value:02 place:2 evaluates to 'Two Hunderd'
       value:34 place:1 evaluates to 'Thirty Four'
       Resulting in string 'One Thousand Two Hundred Thirty Four'
       
       Translator Algorithm
       ====================
       
       Each pair contains two digit. 
       
       1. Separate first digit and postfix it with '0' character.
       Translate it into its equivalent string represenation. 
       Don't do anything if value is Zero.
       (34 -> 3 + '0' -> 30 -> Thirty)
       
       2. Take second digit and put its
       corresponding string representation.
       (34 -> 4 -> Four)
       Don't do anything if value is Zero.
       
       3. Take place value and translate it to represent actual place of 
       this string pair in whole number.
       (3 -> 3-1 -> 2 -> Thousand)
       Don't do anything if place is Zero.
  -->

  <xsl:template name ="nodeTemplate" match="numbers" >
    <html>
      <h2>Translation of numbers to its place value string representation.</h2>
      <list>
        <li>Number should contain maximum 21 digits.</li>
        <li>Number should not contain any non-numeric character.</li>
        <li>No plus(+) or minus(-) signs should be used.</li>
      </list>
      <br />
      <br />
      If above criterian is not followed this transformation can give unpredictable results.      
      <hr />
      <xsl:apply-templates />
    </html>
  </xsl:template>
  <!-- For each number value represent original number and then call template
       to translate it to string representation. After then put a divider line
       and continue with next.
       It generates an output as:
       
       ______________________________________________________
       Number #######
       ## ##### #### ###### #####
       ______________________________________________________
       Number #######
       ## ##### #### ###### #####
       ______________________________________________________
       
       -->
  <xsl:template match="number">
    Number: <xsl:value-of select="."/>
    <br />
    <xsl:call-template name="normalizeValue" >
      <xsl:with-param name="value" select="."/>
    </xsl:call-template>
    <br />
    <hr />    
  </xsl:template>

  <!--normalizevalue template checks if string length of number is greater than 3. 
      It means it contains a hundred place value in between. In Indian number system
      only hundred place value is evaluated for single digit, rest all have pair 
      digits. So for our homogenious template calling convenience we put a '0' character 
      with hundred place value thus making each place value having a pair of digits. e.g
      31423 will be normalized to 310423 which can be broken as 31-04-23. So now we have 
      an easy thing to do, means translate pair of digits rather than worrying about 
      handling a hundred place value exceptional case.-->
  <xsl:template name="normalizeValue">
    <xsl:param name="value"/>

    
    <xsl:if test="string-length($value)&gt;21">
      <b>Overflow. Maximim 21 Digits.</b>
    </xsl:if>
    
    <!--If string length is greater than 3.-->
    <xsl:if test="string-length($value)&gt;3 and string-length($value)&lt;=21">

      <!--Find index where we will insert '0' character.-->
      <xsl:variable name="insertIndex" select="string-length($value)-3"/>

      <!--Convert number to string.-->
      <xsl:variable name="stringValue" select="$value"/>

      <!--Insert '0' at the specified index.-->
      <xsl:variable name="newValue" select="concat(substring($stringValue,1,$insertIndex),'0',substring($stringValue,$insertIndex + 1,3))" />

      <!--Make next call to make this generated string having even number of digits.-->
      <xsl:call-template name="evenVariable">
        <xsl:with-param name="value" select="$newValue" />
      </xsl:call-template>
    </xsl:if>

    <!--If string having length less than 3 means we don't need to bother about hundred
        place value.-->
    <xsl:if test="string-length($value)&lt;=3">
      <xsl:call-template name="evenVariable">
        <xsl:with-param name="value" select="$value" />
      </xsl:call-template>
    </xsl:if>

  </xsl:template>

  <!--Since we are parsing pair of digits so it is possible that left most digit have no pairs.
      We resolve this issue by prefixing a '0' digit. This is again to make sure that we have
      each place value is in paired mode. i.e 10124 will be translated to 010124 which can be 
      then broken in pairs as 01-01-24. We also calculate the left most pair (Most significant pair)
      place position which helps us to determine its place value. We get it by dividing the length 
      of string by two since each place value is paired now.-->
  <xsl:template name="evenVariable">
    <xsl:param name="value"></xsl:param>

    <!--If string have odd number of characters.-->
    <xsl:if test="string-length($value) mod 2 != 0">

      <!--Prefix string with a '0' character and call breakup function with even length string and
          its largest place value.-->
      <xsl:call-template name="performBreakup" >
        <xsl:with-param name="value" select="concat('0', $value)" />
        <xsl:with-param name="place" select="format-number(string-length(concat('0', $value)) div 2,'#')" />
      </xsl:call-template>
    </xsl:if>

    <!--If string is already having even number of digits call breakup function with even length string 
        and its largest place value.-->
    <xsl:if test="string-length($value) mod 2 = 0">
      <xsl:call-template name="performBreakup" >
        <xsl:with-param name="value" select="$value" />
        <xsl:with-param name="place" select="format-number((string-length($value) div 2),'#')" />
      </xsl:call-template>
    </xsl:if>

  </xsl:template>

  <!--The perform breakup template ultimately start extracting each pair and pass it to translator which
      converts this pair to its equivalent string represenatation. This template also determins current
      pairs place in string on a regular reducing basis. So what it does it sends each pair in number to
      translator with its place position. e.g 1234 will be sent as pair:12, place:2 and after then it will 
      call itself with value value:34,place:(2-1 = 1) unless each pair is translated and place value 
      becomes -1.-->
  <xsl:template name="performBreakup">
    <xsl:param name="value" />
    <xsl:param name="place" />

    <!--Check if passed pair of digits having value equivalent to greater than Zero.-->
    <xsl:if test="$place&gt;=0">

      <!--Make call for Most significant digit pair with its place value.-->
      <xsl:call-template name="translateValue">
        <xsl:with-param name="value" select="substring($value,1,2)" />
        <xsl:with-param name="place" select="$place"/>
      </xsl:call-template>

      <!--Make call for Next Most significant digit pair with its reduced place value. i.e.
          Move to next pair.-->
      <xsl:call-template name="performBreakup" >
        <xsl:with-param name="value" select="substring($value,3,string-length($value)-2)" />
        <xsl:with-param name="place" select="$place - 1" />
      </xsl:call-template>
    </xsl:if>

  </xsl:template>

  <!--translate value template takes pair value and its position in string as argument then break this
  pair in individual digits and send it to final translator and then based upon place value it place the 
  place value identifier after translated string. e.g value:45, place:3 will be translated as 
  value:40 = Fourty,value:5 = Five put place at 3 = Thousand, giving a final result as 'Fourty Five Thousand'
  -->
  <xsl:template name="translateValue">
    <xsl:param name="value" />
    <xsl:param name="place" />

    <xsl:if test="$value&gt;20">
      <!--Translate Most significant digit in current pair.-->
      <xsl:call-template name="convertToString">
        <xsl:with-param name="value" select="concat(substring($value,1,1),'0')" />
      </xsl:call-template>

      <!--Translate Lest significant digit in current pair.-->
      <xsl:call-template name="convertToString">
        <xsl:with-param name="value" select="substring($value,2,1)" />
      </xsl:call-template>
    </xsl:if>

    <xsl:if test="$value&lt;=20">
      <!--Translate Most significant digit in current pair.-->
      <xsl:call-template name="convertToString">
        <xsl:with-param name="value" select="$value" />
      </xsl:call-template>
    </xsl:if>
    
    <!--We use deffered place for translation which is less than 1 from actual place since actual place also contain
        last pair of value which have no place value string associated with it.-->
    <xsl:if test="$value &gt; 0">
      <xsl:variable name="defferedPlace" select="$place - 1" />
      <xsl:choose>
        <xsl:when test="$defferedPlace=0"></xsl:when>
        <xsl:when test="$defferedPlace=1">Hundred </xsl:when>
        <xsl:when test="$defferedPlace=2">Thousand </xsl:when>
        <xsl:when test="$defferedPlace=3">Lakh </xsl:when>
        <xsl:when test="$defferedPlace=4">Crore </xsl:when>
        <xsl:when test="$defferedPlace=5">Arab </xsl:when>
        <xsl:when test="$defferedPlace=6">Kharab </xsl:when>
        <xsl:when test="$defferedPlace=7">Neel </xsl:when>
        <xsl:when test="$defferedPlace=8">Padma </xsl:when>
        <xsl:when test="$defferedPlace=9">Sankh </xsl:when>
        <xsl:when test="$defferedPlace=10">Mahasankh </xsl:when>
      </xsl:choose>
    </xsl:if>
  </xsl:template>

  <!--convert to string method does only translation of number to its string representation. It have
      all the unit conversion strings in it.-->
  <xsl:template name ="convertToString">
    <xsl:param name="value"></xsl:param>

    <xsl:choose>
      <xsl:when test="$value=0" />
      <xsl:when test="$value=1">One </xsl:when>
      <xsl:when test="$value=2">Two </xsl:when>
      <xsl:when test="$value=3">Three </xsl:when>
      <xsl:when test="$value=4">Four </xsl:when>
      <xsl:when test="$value=5">Five </xsl:when>
      <xsl:when test="$value=6">Six </xsl:when>
      <xsl:when test="$value=7">Seven </xsl:when>
      <xsl:when test="$value=8">Eight </xsl:when>
      <xsl:when test="$value=9">Nine </xsl:when>
      <xsl:when test="$value=10">Ten </xsl:when>
      <xsl:when test="$value=11">Eleven </xsl:when>
      <xsl:when test="$value=12">Twelve </xsl:when>
      <xsl:when test="$value=13">Thirteen </xsl:when>
      <xsl:when test="$value=14">Fourteen </xsl:when>
      <xsl:when test="$value=15">Fifteen </xsl:when>
      <xsl:when test="$value=16">Sixteen </xsl:when>
      <xsl:when test="$value=17">Seventeen </xsl:when>
      <xsl:when test="$value=18">Eighteen </xsl:when>
      <xsl:when test="$value=19">Nineteen </xsl:when>
      <xsl:when test="$value=20">Twenty </xsl:when>
      <xsl:when test="$value=30">Thirty </xsl:when>
      <xsl:when test="$value=40">Fourty </xsl:when>
      <xsl:when test="$value=50">Fifty </xsl:when>
      <xsl:when test="$value=60">Sixty </xsl:when>
      <xsl:when test="$value=70">Seventy </xsl:when>
      <xsl:when test="$value=80">Eighty </xsl:when>
      <xsl:when test="$value=90">Ninety </xsl:when>
    </xsl:choose>

  </xsl:template>
</xsl:stylesheet>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader M*Modal
India India
Started carreer with CEERI, Delhi, India as a C Programmer in 2004 and migrated my learning experiance to C#.Net in 2005 with DIGISIGN Noida, Joined Bally in 2006, worked with JK Technosoft since Jun 2007 till Apr 2009, joined back Bally in June 2009 and joined Misys in June 2010. Worked in different domains such as Casino Management, Digital Signage, and Medical and currently working M*Modal as Lead - Product Development.

Comments and Discussions