RE: [xsl] Create a bit mask ?

Subject: RE: [xsl] Create a bit mask ?
From: <Jarno.Elovirta@xxxxxxxxx>
Date: Wed, 10 Nov 2004 09:07:12 +0200
Hi,

> I need to convert a number of elements into a single
> element with a bit mask as its value. Here is a some
> sample source XML snippet:
>
> <Rule Name="Rule1">
> 	<Tag Name="Tag1"/>
> 	<Tag Name="Tag2"/>
> </Rule>
> <Rule Name="Rule2">
> 	<Tag Name="Tag1"/>
> 	<Tag Name="Tag3"/>
> </Rule>
>
> <Tags>
> 	<Tag Name="Tag1">
> 		<Id>0</Id>
> 	</Tag>
> 	<Tag Name="Tag2">
> 		<Id>1</Id>
> 	</Tag>
> 	<Tag Name="Tag3">
> 		<Id>2</Id>
> 	</Tag>
> </Tags>
>
>
> I need to convert this into:
>
> <Rule Name="Rule1">
> 	<TagMap>-4</TagMap>
> </Rule>
> <Rule Name="Rule2">
> 	<TagMap>-6</TagMap>
> </Rule>
>
> The value in TagMap is a 32 bit bit-mask which
> contains a 0 if the Tag applies to the rule and a 1 if
> it does not. The bit position for a tag is determined
> by the Tag's ID value (Starting from the right most
> bit)
>
> So the map for Rule1 is -4 which is
> 11111111111111111111111111111100 in binary. The two
> zeros correspond to Tag1 (Id 0) and Tag2 (Id 1).
> Map value for Rule2 is -6 which is
> 11111111111111111111111111111010 corresponding to Tag1
> (Id 0) and Tag3 (Id 2).
>
> Can anyone help with this? I feel handicapped without
> a processing loop construct and being able to redefine
> the value of a variable! I am limited to using XSLT
> 1.0

How does 11111111111111111111111111111100 represent -4 in binary? If I reverse
the ones and zeros (what ever you call that operation in English), add one,
and multiply with -1 I get the results you state. Anyhow, the stylesheet below
gives you what you wanted, but as I didn't really get the mask to value
conversion, you may have to rewrite it. The Bin2Dec template's from
Xselerator's Standard Snippet Library, don't know who wrote it.

  <xsl:template match="Rule">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <TagMap>
        <xsl:variable name="n">
          <xsl:call-template name="Bin2Dec">
            <xsl:with-param name="value">
              <xsl:apply-templates select="Tag[1]"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:variable>
        <xsl:value-of select="-($n + 1)"/>
      </TagMap>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="Tag">
    <xsl:param name="mask" select="'00000000000000000000000000000000'"/>
    <xsl:variable name="id" select="32 - ../../Tags/Tag[@Name =
current()/@Name]/Id"/>
    <xsl:choose>
      <xsl:when test="following-sibling::Tag">
        <xsl:apply-templates select="following-sibling::Tag[1]">
          <xsl:with-param name="mask" select="concat(substring($mask, 0, $id),
1, substring($mask, $id + 1, 32))"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat(substring($mask, 0, $id), 1,
substring($mask, $id + 1, 32))"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <xsl:template match="Tags"/>
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  <!-- ========================================================= -->
  <!-- Function: Bin2Dec(<value>) => Decimal value               -->
  <!-- Parameters:-                                              -->
  <!--   <value>  - the binary string to be converted to decimal -->
  <xsl:template name="Bin2Dec">
    <xsl:param name="value" select="'0'"/>
    <!-- the following paremeters are used only during recursion -->
    <xsl:param name="bin-power" select="number(1)"/>
    <xsl:param name="accum" select="number(0)"/>
    <!-- isolate last binary digit  -->
    <xsl:variable name="bin-digit"
select="substring($value,string-length($value),1)"/>
    <!-- check that binary digit is valid -->
    <xsl:choose>
      <xsl:when test="not(contains('01',$bin-digit))">
        <!-- not a binary digit! -->
        <xsl:text>NaN</xsl:text>
      </xsl:when>
      <xsl:when test="string-length($bin-digit) = 0">
        <!-- unexpected end of hex string -->
        <xsl:text>0</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <!-- OK so far -->
        <xsl:variable name="remainder"
select="substring($value,1,string-length($value)-1)"/>
        <xsl:variable name="this-digit-value" select="number($bin-digit) *
$bin-power"/>
        <!-- determine whether this is the end of the hex string -->
        <xsl:choose>
          <xsl:when test="string-length($remainder) = 0">
            <!-- end - output final result -->
            <xsl:value-of select="$accum + $this-digit-value"/>
          </xsl:when>
          <xsl:otherwise>
            <!-- recurse to self for next digit -->
            <xsl:call-template name="Bin2Dec">
              <xsl:with-param name="value" select="$remainder"/>
              <xsl:with-param name="bin-power" select="$bin-power * 2"/>
              <xsl:with-param name="accum" select="$accum +
$this-digit-value"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

Cheers,

Jarno

Current Thread
  • [xsl] Create a bit mask ?
    • Saba - Tue, 9 Nov 2004 13:54:09 -0800 (PST)
      • <Possible follow-ups>
      • Jarno.Elovirta - Wed, 10 Nov 2004 09:07:12 +0200 <=
        • Saba - Wed, 10 Nov 2004 10:57:52 -0800 (PST)