By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,296 Members | 1,469 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,296 IT Pros & Developers. It's quick & easy.

Calculate attributes with XSLT

P: n/a
Hello,
I want to calculate the value of an attribute. For example <rect x="2+3"
y="12"and be <rect x="5" y="12">. Is it possible using XSLT?

Thanks!
Oct 31 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Carles Company Soler wrote:
I want to calculate the value of an attribute. For example <rect x="2+3"
y="12"and be <rect x="5" y="12">. Is it possible using XSLT?
<rect x="{2 + 3}" y="12">...</rect>
The attribute value is interpreted as an attribute value template where
{} contains an XPath expression, in that example simply one adding two
numbers given as literals but of course you can have more complex XPath
expressions as needed to compute the attribute value.

--

Martin Honnen
http://JavaScript.FAQTs.com/
Oct 31 '06 #2

P: n/a
Carles Company Soler wrote:
I want to calculate the value of an attribute. For example <rect x="2+3"
y="12"and be <rect x="5" y="12">. Is it possible using XSLT?
Yes, but.

XSLT can certainly perform math, since the XPath language can do so. So
if the expression appears in the stylesheet, this is trivial.

But XSLT doesn't normally have the ability to interpret expressions
found in the input document rather than the stylesheet. Since that seems
to be what you want, you'll have to do some more work -- essentially,
you'll have to use XSLT as a programming language to implement an
expression interpreter, doing the string operations to break up the
expression into values and operators and executing the appropriate
operations.

This has certainly been done, and I suspect a websearch will dig up some
examples. It isn't difficult if you have any experience with
recursive-descent parsing, it's just a nuisance.

Alternatively, some XSLT processors support the "dynamic" section of the
EXSLT extension function library. This permits executing XPath
expressions found in arbitrary string data. It's overkill for your
stated needs, and of course relying on an extension function makes your
stylesheet less portable, but it is another alternative. (Or you could
plug in your own custom extension function, but obviously that's another
step away from portability.)

--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
Oct 31 '06 #3

P: n/a

Carles Company Soler wrote:
I want to calculate the value of an attribute. For
example <rect x="2+3" y="12"and be <rect x="5" y="12">.
Is it possible using XSLT?
It sure is, BUT. It's really not what XSLT is for: you'd
have to write your own expression evaluator, and XSLT is
ill-suited for that. If you need that type of processing,
you'd better use something else, or wait for XSLT 2.0 to
become Recommendation -- I believe it's much easier to do
something like that with XSLT2. EXSLT is probably an
option, too, but that's something I'd try to avoid if at
all possible.

Just for the heck of it, simple arithmetics-only:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ops="http://www.example.org/Operators">
<ops:ops>
<ops:op name="+"/><ops:op name="-"/>
<ops:op name="*"/><ops:op name="/"/>
</ops:ops>
<xsl:output method="xml"/>
<xsl:template match="ops:op[@name='+']" mode="eval">
<xsl:param name="l"/><xsl:param name="r"/>
<xsl:value-of select="$l+$r"/>
</xsl:template>
<xsl:template match="ops:op[@name='-']" mode="eval">
<xsl:param name="l"/><xsl:param name="r"/>
<xsl:value-of select="$l - $r"/>
</xsl:template>
<xsl:template match="ops:op[@name='*']" mode="eval">
<xsl:param name="l"/><xsl:param name="r"/>
<xsl:value-of select="$l*$r"/>
</xsl:template>
<xsl:template match="ops:op[@name='/']" mode="eval">
<xsl:param name="l"/><xsl:param name="r"/>
<xsl:value-of select="$l div $r"/>
</xsl:template>
<xsl:template name="eval">
<xsl:param name="l"/>
<xsl:param name="x"/>
<xsl:variable name="car" select="substring($x,1,1)"/>
<xsl:variable name="cdr" select="substring($x,2)"/>
<xsl:choose>
<xsl:when test="document('')//ops:op[@name=$car]">
<xsl:apply-templates
select="document('')//ops:op[@name=$car]"
mode="eval">
<xsl:with-param name="l" select="$l"/>
<xsl:with-param name="r">
<xsl:call-template name="eval">
<xsl:with-param name="l" select="''"/>
<xsl:with-param name="x" select="$cdr"/>
</xsl:call-template>
</xsl:with-param>
</xsl:apply-templates>
</xsl:when>
<xsl:when test="$car">
<xsl:call-template name="eval">
<xsl:with-param name="l"
select="concat($l,$car)"/>
<xsl:with-param name="x"
select="$cdr"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$l"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:call-template name="eval">
<xsl:with-param name="l" select="''"/>
<xsl:with-param name="x" select="."/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Note that it's totally unaware of precedence. (It actually
calculates the right-most expression first. D'oh.) It can
recurse itself unto death really fast, too. And I don't
even mention precision problems it seems to be suffering
from (well, I suppose that's processor-dependent).

--
Pavel Lepin

Oct 31 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.