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

xsl totals composed from variables

P: n/a
Dear reader,

I am trying some things with xml/xsl and cannot find a solution for
what I would like to do.

I have 2 base items with name and price and two that are composed of
base two (given name and quantity).
The composition never changes, only the price can change.
I can calculate the total value (price*quantity) with a for-each loop
(using xsl:key) for each set of components, listing below.

But now I want to calculate the total value of the components used in
the composed items.

I have looked into a 'loop' template, but this does not give the
results I want.
I tried various layouts, but only get a NaN value or the original value
passed to the loop.

I inserted the loop call right after I got the value p
(price*quantity).

Could someone point me to a working solution?

Thanks

Jos
------- loop template -----------
<xsl:template name="loop">
<xsl:param name="pr"/>
<xsl:param name="t" select="0"/<!-- not sure about this one -->
<xsl:choose>
<xsl:when test="$pr">
<xsl:call-template name="loop">
<xsl:with-param name="t" select="$pr+$t"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$t" />
</xsl:otherwise>
</xsl:choose>

</xsl:template>
Call:
<xsl:call-template name="loop">
<xsl:with-param name="pr" select="$p"/>
</xsl:call-template>

---- working code -----
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:key name="comp" match="item" use="name" />
<xsl:template match="/">
<table border="1">
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="item">
<tr><td><xsl:value-of select="name" /</td>
<td><xsl:value-of select="price" /></td>
<xsl:for-each select="component">
<td><xsl:value-of select="cname" /></td>
<td><xsl:value-of select="quantity" /></td>
<xsl:variable name="cn" select="cname" />
<xsl:variable name="q" select="quantity" />

<xsl:for-each select="key('comp', $cn)">
<xsl:variable name="p" select="price*$q" />
<td><xsl:value-of select="$p"/></td>
</xsl:for-each>

<!-- <xsl:value-of select="quantity" /-->
</xsl:for-each>
</tr>
</xsl:template>

</xsl:stylesheet>

---- Sample XML ----

<items>
<item>
<name>A</name>
<price>10</price>
</item>
<item>
<name>B</name>
<price>20</price>
</item>
<item>
<name>C</name>
<price>10</price>
<component>
<cname>A</cname>
<quantity>2</quantity>
</component>
<component>
<cname>B</cname>
<quantity>5</quantity>
</component>
</item>
<item>
<name>D</name>
<price>10</price>
<component>
<cname>A</cname>
<quantity>2</quantity>
</component>
<component>
<cname>B</cname>
<quantity>5</quantity>
</component>
</item>
</items>

Nov 3 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Very unclear explanation -- try to provide a better one.

Cheers,
Dimitre Novatchev
"the_jos" <th******@yahoo.comwrote in message
news:11**********************@e3g2000cwe.googlegro ups.com...
Dear reader,

I am trying some things with xml/xsl and cannot find a solution for
what I would like to do.

I have 2 base items with name and price and two that are composed of
base two (given name and quantity).
The composition never changes, only the price can change.
I can calculate the total value (price*quantity) with a for-each loop
(using xsl:key) for each set of components, listing below.

But now I want to calculate the total value of the components used in
the composed items.

I have looked into a 'loop' template, but this does not give the
results I want.
I tried various layouts, but only get a NaN value or the original value
passed to the loop.

I inserted the loop call right after I got the value p
(price*quantity).

Could someone point me to a working solution?

Thanks

Jos
------- loop template -----------
<xsl:template name="loop">
<xsl:param name="pr"/>
<xsl:param name="t" select="0"/<!-- not sure about this one -->
<xsl:choose>
<xsl:when test="$pr">
<xsl:call-template name="loop">
<xsl:with-param name="t" select="$pr+$t"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$t" />
</xsl:otherwise>
</xsl:choose>

</xsl:template>
Call:
<xsl:call-template name="loop">
<xsl:with-param name="pr" select="$p"/>
</xsl:call-template>

---- working code -----
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:key name="comp" match="item" use="name" />
<xsl:template match="/">
<table border="1">
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="item">
<tr><td><xsl:value-of select="name" /</td>
<td><xsl:value-of select="price" /></td>
<xsl:for-each select="component">
<td><xsl:value-of select="cname" /></td>
<td><xsl:value-of select="quantity" /></td>
<xsl:variable name="cn" select="cname" />
<xsl:variable name="q" select="quantity" />

<xsl:for-each select="key('comp', $cn)">
<xsl:variable name="p" select="price*$q" />
<td><xsl:value-of select="$p"/></td>
</xsl:for-each>

<!-- <xsl:value-of select="quantity" /-->
</xsl:for-each>
</tr>
</xsl:template>

</xsl:stylesheet>

---- Sample XML ----

<items>
<item>
<name>A</name>
<price>10</price>
</item>
<item>
<name>B</name>
<price>20</price>
</item>
<item>
<name>C</name>
<price>10</price>
<component>
<cname>A</cname>
<quantity>2</quantity>
</component>
<component>
<cname>B</cname>
<quantity>5</quantity>
</component>
</item>
<item>
<name>D</name>
<price>10</price>
<component>
<cname>A</cname>
<quantity>2</quantity>
</component>
<component>
<cname>B</cname>
<quantity>5</quantity>
</component>
</item>
</items>

Nov 4 '06 #2

P: n/a
Dimitre Novatchev wrote:
Very unclear explanation -- try to provide a better one.
For example: Show us what output you're trying to get, and explain
specifically how that output was obtained.

Or, if you want to figure this out yourself: Put some output (either
document output, or xsl:message calls) into your loop template,
displaying the values of your variables. The first thing you'll discover
is that because you failed to explicitly pass $pr into the recursion, it
isn't set the second time through, so your "loop" isn't doing much looping.
--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
Nov 4 '06 #3

P: n/a
For example:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:key name="comp" match="item" use="name" />
<xsl:template match="/">
<table border="1">
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="item">
<tr><td><xsl:value-of select="name" /</td>
<td><xsl:value-of select="price" /></td>
<xsl:for-each select="component">
<td><xsl:value-of select="cname" /></td>
<td><xsl:value-of select="quantity" /></td>
<xsl:variable name="cn" select="cname" />
<xsl:variable name="q" select="quantity" />

<xsl:for-each select="key('comp', $cn)">
<xsl:variable name="p" select="price*$q" />
<td><xsl:value-of select="$p"/></td>

---------------------------
Test (must be within scope of the $p variable):

<xsl:call-template name="loop">
<xsl:with-param name="pr" select="$p"/>
</xsl:call-template>
---------------------------

</xsl:for-each>

<!-- <xsl:value-of select="quantity" /-->
</xsl:for-each>
</tr>

</xsl:template>

<xsl:template name="loop">
<xsl:param name="pr"/>
<xsl:param name="t" select="0"/>
<xsl:message>pr=<xsl:value-of select="$pr"/>, t=<xsl:value-of
select="$t"/></xsl:message>
<xsl:choose>
<xsl:when test="$pr">
<xsl:call-template name="loop">
<xsl:with-param name="t" select="$pr+$t"/>
<!-- I presume you meant to add: -->
<xsl:with-param name="pr" select="$pr -1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$t" />
</xsl:otherwise>
</xsl:choose>

</xsl:template>
</xsl:stylesheet>

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

P: n/a

Joe Kesselman wrote:
Dimitre Novatchev wrote:

For example: Show us what output you're trying to get, and explain
specifically how that output was obtained.

Or, if you want to figure this out yourself: Put some output (either
document output, or xsl:message calls) into your loop template,
displaying the values of your variables. The first thing you'll discover
is that because you failed to explicitly pass $pr into the recursion, it
isn't set the second time through, so your "loop" isn't doing much looping.
Joe,

Thanks for the reply.
I'll look into your example and your surgestion above tomorrow (it's
getting late here in Europe).

I'm trying to get a better understanding about xml/xsl and am trying to
do that with something that interests me. So I am trying to build a xml
document that determines the minimum net. value of some components in
an online game.
I can do this in a program language (like java), but am looking for a
more code-independent solution. I then found out that xml/xsl does not
handle variables the way a program language does. But that's not
entirely strange, given the nature of xsl.

Let's give a somewhat real-life example:

Lets say I want a table set.

I know the components are:
4 chairs and one table.
A chair is 4 legs and one chair_top.
A table is 4 legs and one table_top.
A table_top is 2 hours of work and 2 wood. Or 100 euro's
A chair_top is 1 hour of work and 1 wood. Or 50 euro's.
Legs are 1 hour of work and 1 wood. Or 25 euro's.

Wood is 5 euro's, work is 20 euro's.
Prices vary, but components remain the same.

For my question, I just wanted to determine the value of legs (25),
chair_top (25) and table_top (50) given the price of wood and work.

I figured out that when I have those values, I can determine the
minimum value of those components.
Given that, I can determine the minimum value of chair and table and
with those the minimum value of 'table_set'.
There willl be various combinations for table_set (like 6 chairs/one
table, 4 chairs /2 tables).
So I figured to make 2 xml sets.
One for each final table_set. This one contains the set name and the
number of tables/chairs.
And one for the base components (in this case wood and work) and the
various combined components (like the legs and tops and ultimate
tables/chairs).

The table_set will inherent / import the data from the list of
base/combined components, which are 'processed' so they will only give
the minimum values.
So when I look up 'table', it calculates building legs and table_top,
determines if building or buying is cheaper, calculate the minimum
value for table based on those results and returns that value.

This would lead to a layout like:
Table_set 1: Tables=1 Chairs=4 Price=650 (150+500)
Table_set 2: Tables=2 Chairs=6 Price=900 (150+750)

Now that I'm thinking about it, is it best to handle the 'combined'
components in the xsl file (put price in xml file and the 'combining
logic' in xsl). Or should I just leave it the way it is right now?

I think I will be working on this idea for the next weeks, but that's
part of learning something new.
It won't be a big xml set for the base components.
I think there's 20 base materials (like wood and work) and 15 combined
(like legs/tops).
The 'table' and 'chair' components are rare, I think there are about 4.
So I figured handling this with xsl should not cause too much resource
problems.

Nov 5 '06 #5

P: n/a
the_jos wrote:
I then found out that xml/xsl does not
handle variables the way a program language does. But that's not
entirely strange, given the nature of xsl.
Actually, XSLT handles variables very much the same way other
nonprocedural programming langauges do -- single-assignment, lexically
scoped.
For my question, I just wanted to determine the value of legs (25),
chair_top (25) and table_top (50) given the price of wood and work.
This is as much a data-representation problem as a stylesheet problem.
If your data hierarchy matches the structural hierarchy, gathering the
structured information becomes much easier -- for example, if the data
is something like

<set>
<table quantity="1">
<top quantity="1" hours="2" wood="2" price="100"/>
<leg quantity="4" hours="1" wood="1" price="25"/>
</table>
<chair quantity="4">
<top quantity="1" hours="1" wood="1" price="50"/>
<leg quantity="4" hours="1" wood="1" price="25"/>
</chair>
</set>

then this becomes a fairly straightforward recursive
multiply-and-accumulate problem. (Value at any node is sum of values of
its children times their quantity, plus its own value if any.) That
isn't necessarily the best solution; there are several other possible
ways to structure this.

Note that this provides all the information in a single document. If you
really wanted to separate the values from the

Picking the minimum of two results is simple once you've got the values,
of course.
This isn't a typical use of XSLT, of course. It's more typical of what
one will do using XQuery... but XQuery and XSLT 2.0 are essentially the
same language with different syntax.
--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
Nov 6 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.