[xsl] base64string to hexstring conversion

Subject: [xsl] base64string to hexstring conversion
From: Hermann Stamm-Wilbrandt <STAMMW@xxxxxxxxxx>
Date: Fri, 4 Sep 2009 22:35:36 +0200
Hello,

in misreading "rendering" as "parsing" in article "[xsl] PDF content
rendering" I thought
about "parsing" a base64 string within XSLT.

My question was how to easiliy provide these three functions:
- contains-base64(base64string,hex-/base64-string)
- substring-after-base64(base64string, hex-/base64-string)
- substring-before-base64(base64string, hex-/base64-string)

Since the search string might consume 2 bits in front and tail base64
character one
would have to  search for up to 16 different base64 strings in the input
base64string.
While this is fine for the first function it is at least more complex for
the others to
identify the first match.

Therefore the easiest solution seems to be a transformation from
base64string to
hexstring (Base64ToHex) and then do simple string operations on the
hexstring.


For XSLT 2 processors this is one solution:
xs:hexBinary(xs:base64Binary(.))

For XSLT 1 processor with extension functions to do so, use it (at least
for efficiency reasons).
Eg, DataPower processor provides extension function
"dp:radix-convert(data, input-radix, output-radix)" which may be used.
To avoid problems with elimination of leading 0s of the "numbers" this
works
(prepending 0xF0 and then remove it, again):
  substring(dp:radix-convert(dp:concat-base64('8A==',$b64str),64,16),3)

For XSLT 1 processor without a helping extension function, I came up with
below solution.

Is there anything I missed?
Is there a better way to do the conversion in XSLT 1?
(see http://en.wikipedia.org/wiki/Base64#Example)


( http://stamm-wilbrandt.de/en/xsl-list/Base64ToHex.xsl )
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>

  <xsl:output method="xml"/>

<!--
  Decode base64 encoded string as hex string.
-->
  <xsl:template name="Base64ToHex">
    <xsl:param name="str"/>
    <xsl:call-template name="Base64ToHexRec">
      <xsl:with-param name="str" select="translate(
        normalize-space($str),' ','')"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="Base64ToHexRec">
    <xsl:param name="str"/>
    <xsl:variable name="len" select="string-length($str)"/>
    <xsl:choose>
      <xsl:when test="$len = 0"/>
      <xsl:when test="$len &gt; 4">
        <xsl:variable name="mid" select="4*floor($len div 8)"/>
        <xsl:call-template name="Base64ToHexRec">
          <xsl:with-param name="str" select="substring($str,1,$mid)"/>
        </xsl:call-template>
        <xsl:call-template name="Base64ToHexRec">
          <xsl:with-param name="str" select="substring($str,$mid+1)"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
<!--
  Decode base64 encoded string of length 4 as hex string of length 2/4/6.

  |111122|223333|444455|556666|

  result hex digits:
  1,2 always
  3,4 if '444455' != '='
  5,6 if '556666' != '='
-->
        <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
'0000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF='),
        1,1)"/>

        <xsl:variable name="h2b1" select="substring(translate($str,),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'0123012301230123012301230123012301230123012301230123012301230123='),
        1,1)"/>

        <xsl:choose>
          <xsl:when test="$h2b1 = '0'">
            <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'0000000000000000111111111111111122222222222222223333333333333333='),
            2,1)"/>
          </xsl:when>

          <xsl:when test="$h2b1 = '1'">
            <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'4444444444444444555555555555555566666666666666667777777777777777='),
            2,1)"/>
          </xsl:when>

          <xsl:when test="$h2b1 = '2'">
            <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'88888888888888889999999999999999AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB='),
            2,1)"/>
          </xsl:when>

          <xsl:when test="$h2b1 = '3'">
            <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'CCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFF='),
            2,1)"/>
          </xsl:when>
        </xsl:choose>

        <xsl:if test="not(contains($str,'=='))">
          <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF='),
          2,1)"/>

          <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'0000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF='),
          3,1)"/>

          <xsl:if test="not(contains($str,'='))">
            <xsl:variable name="h2b2" select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
'0123012301230123012301230123012301230123012301230123012301230123='),
            3,1)"/>

            <xsl:choose>
              <xsl:when test="$h2b2 = '0'">
                <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'0000000000000000111111111111111122222222222222223333333333333333='),
                4,1)"/>
              </xsl:when>

              <xsl:when test="$h2b2 = '1'">
                <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'4444444444444444555555555555555566666666666666667777777777777777='),
                4,1)"/>
              </xsl:when>

              <xsl:when test="$h2b2 = '2'">
                <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'88888888888888889999999999999999AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB='),
                4,1)"/>
              </xsl:when>

              <xsl:when test="$h2b2 = '3'">
                <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'CCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFF='),
                4,1)"/>
              </xsl:when>
            </xsl:choose>

            <xsl:value-of select="substring(translate($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',,
'0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF='),
            4,1)"/>

          </xsl:if>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <xsl:template match="/">
    <hex>
      <xsl:call-template name="Base64ToHex">
        <xsl:with-param name="str" select="."/>
      </xsl:call-template>
    </hex>
  </xsl:template>

</xsl:stylesheet>


Mit besten Gruessen / Best wishes,

Hermann Stamm-Wilbrandt
Developer, XML Compiler
WebSphere DataPower SOA Appliances
----------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschaeftsfuehrung: Erich Baier
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294

Current Thread