views:

732

answers:

3
+1  Q: 

XSLT Bitwise Logic

I have an existing data set that utilizes an integer to store multiple values; the legacy front end did a simple bitwise check (e.g. in C#: iValues & 16 == 16) to see if a particular value was set. Is it possible to do bitwise operations in XSL, and more explicitly, to do bit level comparisons via masking? The built-in "and" will always result in "true" or "false", but perhaps it's possible via the math operators available?

I'm currently using .NET 2.0, which uses XSLT 1.0.

A: 

XSLT is Turing-complete, see for example here or here, hence it can be done. But I have used XSLT only one or two times and can give no solution.

UPDATE

I just read a tutorial again and found a solution using the following fact. bitset(x, n) returns true, if the n-th bit of x is set, false otherwise.

bitset(x, n) := floor(x / 2^n) mod 2 == 1

The following XSLT

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

  <xsl:template match="/">
    <html>
      <body>
        <table border="1" style="text-align:center;">
          <tr bgcolor="#9acd32">
            <th>Number</th>
            <th>Bit 3</th>
            <th>Bit 2</th>
            <th>Bit 1</th>
            <th>Bit 0</th>
          </tr>
          <xsl:for-each select="numbers/number">
            <tr>
              <td>
                <xsl:value-of select="."/>
              </td>
              <td>
                <xsl:choose>
                  <xsl:when test="floor(. div 8) mod 2 = 1">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </td>
              <td>
                <xsl:choose>
                  <xsl:when test="floor(. div 4) mod 2 = 1">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </td>
              <td>
                <xsl:choose>
                  <xsl:when test="floor(. div 2) mod 2 = 1">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </td>
              <td>
                <xsl:choose>
                  <xsl:when test="floor(. div 1) mod 2 = 1">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

will turn this XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<numbers>
  <number>0</number>
  <number>1</number>
  <number>2</number>
  <number>3</number>
  <number>4</number>
  <number>5</number>
  <number>6</number>
  <number>7</number>
  <number>8</number>
  <number>9</number>
  <number>10</number>
  <number>11</number>
  <number>12</number>
  <number>13</number>
  <number>14</number>
  <number>15</number>
</numbers>

into a HTML document with a table showing the bits of the numbers.

Number | Bit 3 | Bit 2 | Bit 1 | Bit 0 
---------------------------------------
   0   |   0   |   0   |   0   |   0 
   1   |   0   |   0   |   0   |   1 
   2   |   0   |   0   |   1   |   0 
   3   |   0   |   0   |   1   |   1 
   4   |   0   |   1   |   0   |   0 
   5   |   0   |   1   |   0   |   1 
   6   |   0   |   1   |   1   |   0 
   7   |   0   |   1   |   1   |   1 
   8   |   1   |   0   |   0   |   0 
   9   |   1   |   0   |   0   |   1 
  10   |   1   |   0   |   1   |   0 
  11   |   1   |   0   |   1   |   1 
  12   |   1   |   1   |   0   |   0 
  13   |   1   |   1   |   0   |   1 
  14   |   1   |   1   |   1   |   0 
  15   |   1   |   1   |   1   |   1

This is neither elegant nor nice in any way and there are probably much simpler solution, but it works. And given that it is my first contact with XSLT, I am quite satisfied.

Daniel Brückner
How does being Turing-complete datermine the answer whether bitwise operators exist?
Grzegorz Oledzki
If it is Turing-complete, it can calculate every function, hence bitwise operations on integers.
Daniel Brückner
Hmm... I don't get it. I am familiar with the notion of Turing-completeness, but still I can imagine a language that is turing-complete and has no bit-wise operators, i.e. there are no means to split numbers into smaller chunks.
Grzegorz Oledzki
There is no need for bitwise operations - you can emulate them. Take a number of variables (maybe 32), initialize them with zero, and think of them as an array. Take another variable X that contains your input value. Look at the rightmost variable. Is it zero? Set it to one. Is it one? Go from right to left through the array and set all ones to zeros until you find the first zero. Set this to one. Now subtract one from X and interate everything until X is zero. When you reach zero, the array will contain the binary representation of X.
Daniel Brückner
All done with setting a variable to two abitrary symbols 'zero' and 'one', comparing a variable with a symbol, subtracting 1 from a variable, a bit of branching, and a kind of indirect access. And that is still much more then required - you can solve this with much less, you don't need subtraction, for example. So that is what Turing completness is about - you can do exactly the same thing on every turing complete system.
Daniel Brückner
+1  A: 

I haven't seen anything like this in XSLT / XPath. But I've found someone implementing this kind of operations manually. Maybe you could use the same approach, if you really need to.

Grzegorz Oledzki
Nice find; just had to change the named template to accept the number as a parameter and it worked like a champ for any arbitrary value.
pdwetz
+1  A: 

XSLT does not define bitwise operations. If you want them, you have to roll your own.

If you're using XSLT specifically in .NET 2.0 context - that is, XslCompiledTransform class - then the simplest solution is to use a scripting block to introduce a C# function that does it, and then just call that:

<xsl:stylesheet xmlns:bitwise="urn:bitwise">

  <msxsl:script language="CSharp" implements-prefix="bitwise">
  <![CDATA[
    public int and(int x, int y) { return x & y; }
    public int or(int x, int y) { return x | y; }
    ...
  ]]>
  </msxsl:script>

  ...

  <xsl:value-of select="bitwise:and(@foo, @bar)" />
  <xsl:value-of select="bitwise:or(@foo, @bar)" />
  ...

</xsl:stylesheet>

Or you can define the more high-level primitives in a scripting block, such as HasFlag, and then use those.

When loading such a stylesheet, you will need to explicitly enable scripting in it:

XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("foo.xsl",
  new XsltSettings { EnableScript = true },
  new XmlUrlResolver());
Pavel Minaev