Monday, 3 April 2006

XSLT Hex to Decimal Conversion

Here’s a trick I came up with to convert some XML values from hex to decimal.

I made clever (awful?) use of substring-after and substring-before and a string-based lookup table.

Very nasty, but with whats available, very neat:

  <!-- output $hexNumber as decimal, recursive so not too many digits please... -->
  <xsl:template name="HexToDecimal">
    <xsl:param name="hexNumber" />
    <xsl:param name="decimalNumber" >0</xsl:param>
    <!– If there is zero hex digits left, output –>
    <xsl:choose>
      <xsl:when test="$hexNumber">
        <xsl:call-template name="HexToDecimal">
          <xsl:with-param name="decimalNumber" select="($decimalNumber*16)+number(substring-before(substring-after(’00/11/22/33/44/55/66/77/88/99/A10/B11/C12/D13/E14/F15/a10/b11/c12/d13/e14/f15/’,substring($hexNumber,1,1)),’/'))" />
          <xsl:with-param name="hexNumber" select="substring($hexNumber,2)" />
        </xsl:call-template>
      </xsl:when>
      <!– otherwise multiply, and add the next digit, and recurse –>
      <xsl:otherwise>
        <xsl:value-of select="$decimalNumber"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <!– If it begins with 0x then parse it for sure, else return it –>
  <xsl:template name="asDecimal">
    <xsl:param name="number" />
    <xsl:choose>
      <xsl:when test="substring($number,1,2)=’0x’">
        <xsl:call-template name="HexToDecimal">
          <xsl:with-param name="hexNumber" select="substring($number,3)"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$number"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


Invoke with
  <xsl:call-template name="HexToDecimal">
    <xsl:with-param name="hexNumber" select="@hexValueAttribute"/>
  </xsl:call-template>


Or some such

5 comments:

  1. If you are interested in an XSLT 2.0 function converting hex to dec, here we go (snippet):
    invoke with hex:dec(somestring)
    Letters have to be uppercase in this implementation and it works recursively too.

    ReplyDelete
  2. Ups… Where is my code?

    ReplyDelete
  3. Hier is a recursive function that does the same in XSLT 2.0
    <xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
    version=”2.0″
    xmlns:hex=”http://user.com/namespace”
    exclude-result-prefixes=”hex”>
    <!– sample call –>
    <xsl:value-of select=”hex:dec(’ffe4′)”/>
    <xsl:function name=”hex:dec”>
    <xsl:param name=”str”/>
    <xsl:variable name=”len” select=”string-length($str)”/>
    <xsl:value-of
    select=”if (string-length($str) &lt; 1)
    then 0
    else hex:dec(substring($str,1,$len - 1))*16+string-length(substring-before(’0123456789ABCDEF’,substring($str,$len)))”/>
    </xsl:function>
    </xsl:stylesheet>

    ReplyDelete
  4. Version 2 which also works for empty strings (returns the empty string), with lower- and uppercase letters and is (maybe) a bit less clumsy…
    <?xml version=”1.0″ encoding=”UTF-8″?>
    <xsl:stylesheet version=”2.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
    xmlns:hex=”http://user.com/namespace”
    xmlns:uri=”http://user.com/namespace”>
    <xsl:value-of select=”hex:dec(’ffe4′)”/>
    <xsl:function name=”hex:dec”>
    <xsl:param name=”str”/>
    <xsl:if test=”$str != ””>
    <xsl:variable name=”len” select=”string-length($str)”/>
    <xsl:value-of select=”
    if ( $len < 2 ) then
    string-length(substring-before(’0 1 2 3 4 5 6 7 8 9 AaBbCcDdEeFf’,$str)) idiv 2
    else
    hex:dec(substring($str,1,$len - 1))*16+hex:dec(substring($str,$len))
    “/>
    </xsl:if>
    </xsl:function>
    </xsl:stylesheet>

    ReplyDelete
  5. Blessed are they with xslt 2.0 support.
    One day, maybe, xsltproc (libxslt) will be updated to support xslt 2.0, or maybe I’ll finish my xslt 2.0 to xslt 1.0 compiler, making heavy use of temporary files in order to assign rtf to variables.

    ReplyDelete