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(_dot_)Elovirta(_at_)nokia(_dot_)com 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[(_at_)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
--+------------------------------------------------------------------
XSL-List info and archive:
http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to:
http://lists.mulberrytech.com/xsl-list/
or e-mail:
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--+--