8

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.

pdwetz
  • 841
  • 1
  • 9
  • 19

4 Answers4

15

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">

  <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
  • 59,031
  • 16
  • 99
  • 143
  • 2
    How does being Turing-complete datermine the answer whether bitwise operators exist? – Grzegorz Oledzki Jul 09 '09 at 21:15
  • 2
    If it is Turing-complete, it can calculate every function, hence bitwise operations on integers. – Daniel Brückner Jul 09 '09 at 21:42
  • 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 Jul 09 '09 at 21:59
  • 2
    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 Jul 09 '09 at 22:57
  • 2
    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 Jul 09 '09 at 23:02
  • I once wrote my own barebones assembler line debugger on a mainframe. As you describe, starting out with 16 fullwords to emulate my registers. It worked well, except when it hit SVC calls :) – grantwparks May 07 '15 at 16:46
3

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
  • 23,614
  • 16
  • 68
  • 106
  • 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 Jul 09 '09 at 21:35
3

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
  • 99,783
  • 25
  • 219
  • 289
2
<xsl:value-of select="for $n in (128, 64, 32, 16, 8, 4, 2, 1) return if ((floor($var div $n) mod 2) = 1) then 1 else 0"/>

this will return the binary array of your variable (stored in $var)

by the way I used XPath 2.0 to do this

  • 2
    Thanks, but not applicable to .NET framework (as per original question, which sadly is still the case for .NET 4.0). Your solution only works if you're using a 3rd party library with support for XPath 2.0. – pdwetz Feb 25 '11 at 16:24