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.
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.
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.
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());
<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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With