RE: [xsl] Create a bit mask ?

Subject: RE: [xsl] Create a bit mask ?
From: Saba <saba_emailme-xslt@xxxxxxxxx>
Date: Wed, 10 Nov 2004 10:57:52 -0800 (PST)
Thanks Jarno! 

    While waiting for a response I had managed to
fumble through the get it to work - I however liked
the compactness of your solution and am updating my
solution to reduce all the extra variables I was
creating.

Thanks a lot for helping me out.
- Saba

--- Jarno.Elovirta@xxxxxxxxx wrote:

> 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