4

I can almost here you say: "What the @##$# is a hexavigesimal value?"

A hexavigesimal numeral system has a base of twenty-six. Alternatively, base-26 may be represented using only letters of the Latin alphabet. As there are 26 letters in English, base-26 is also the highest base in which this is possible and hence utilizes every letter. 0 is represented by A, 1 = B, 2 = C ... 24 = Y, 25 = Z. Some examples: 26 = AA, 30 = BE

So it is basically what Excel uses a column description. I would like to have a function that converts a node with an int value into this value.

Source:

<root>
  <row>12</row>
  <column>23</column>
</root>

I would like to print column as X by calling a template that does the conversion. Can it be done?

Kees C. Bakker
  • 32,294
  • 27
  • 115
  • 203

3 Answers3

1

Try this XSLT...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:variable name="symbols" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
   <xsl:variable name="symbols-count" select="string-length($symbols)" />
   <xsl:template match="row">
      <row>
      <xsl:call-template name="convert" />
      </row>
   </xsl:template>

   <xsl:template name="convert">
      <xsl:param name="value" select="number(.)" />
      <xsl:choose>
         <xsl:when test="$value >= $symbols-count">
            <xsl:variable name="div" select="floor($value div $symbols-count)" />
            <xsl:variable name="remainder" select="$value - $div * $symbols-count" />
            <xsl:call-template name="convert">
               <xsl:with-param name="value" select="$div" />
            </xsl:call-template>
            <xsl:value-of select="substring($symbols, $remainder + 1, 1)" />
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="substring($symbols, $value + 1, 1)" />
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

When applied to the following XML

<root>
   <row>12</row>
   <column>23</column>
   <row>26</row>
   <column>23</column>
</root>

The following is output

<root>
  <row>M</row>
  <column>23</column>
  <row>BA</row>
  <column>23</column>
</root>

You should be able to adjust the symbols variable to allow any fancy-named-imal conversion. For example, to convert to hexadecimal change it to the following

<xsl:variable name="symbols" select="'0123456789ABCDEF'" />

And to binary

<xsl:variable name="symbols" select="'01'" />
Tim C
  • 70,053
  • 14
  • 74
  • 93
0

You might find that <xsl:number value="$n" format="A"/> does what you want, but it's not guaranteed.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • The spec gives leeway for the processor to "localize" alphabetic numbering for example by adding accented letters to the sequence, or removing letters such as "i" and "o" that are potentially confusing. Also, this sequence goes X, Y, Z, AA, AB, whereas hexavigesimal with A=0 would go X, Y, Z, BA, BB, ... – Michael Kay May 28 '12 at 14:24
0

In XSLT 1.0 use:

 <xsl:template name="toHex">
   <xsl:param name="decimalNumber" />
   <xsl:if test="$decimalNumber >= 16">
     <xsl:call-template name="toHex">
       <xsl:with-param name="decimalNumber" 
              select="floor($decimalNumber div 16)" />
       </xsl:call-template>
   </xsl:if>
   <xsl:value-of select=
      "substring($hexDigits, ($decimalNumber mod 16) + 1, 1)" />
 </xsl:template>

where $hexDigits is the string '0123456789ABCDEF'.

Here is a complete example:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

    <xsl:variable name="hexDigits" select="'0123456789ABCDEF'"/>

    <xsl:template match="/*">
      <xsl:call-template name="toHex"/>
    </xsl:template>

    <xsl:template name="toHex">
        <xsl:param name="decimalNumber" select="." />
        <xsl:if test="$decimalNumber >= 16">
            <xsl:call-template name="toHex">
                <xsl:with-param name="decimalNumber" select=
                  "floor($decimalNumber div 16)" />
            </xsl:call-template>
        </xsl:if>
        <xsl:value-of select=
         "substring($hexDigits, ($decimalNumber mod 16) + 1, 1)" />
    </xsl:template>
</xsl:stylesheet>

When this XSLT 1.0 transformation is applied on this XML document:

<t>12345</t>

the wanted, correct result is produced:

3039

See also my answer to this question:

https://stackoverflow.com/a/3053656/36305

Community
  • 1
  • 1
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431