xslt challenging situation related to iterations

H

hilz

Hi all
I have this situation where I have an xml file similar to this:

<Root>
<MyElement year="2004"><Amount>10</Amount></MyElement>
<MyElement year="2004"><Amount>11</Amount></MyElement>
<MyElement year="2005"><Amount>15</Amount></MyElement>
<MyElement year="2006"><Amount>4</Amount></MyElement>
<MyElement year="2006"><Amount>7</Amount></MyElement>
<MyElement year="2004"><Amount>20</Amount></MyElement>
...
...
</Root>


Now I want to summarize this by transforming it into something like this

<Root>
<MyElement year="2004">
<Amounnt>10</Amount>
<Amounnt>11</Amount>
<Amounnt>20</Amount>
</MyElement>
<MyElement year="2005">
<Amounnt>15</Amount>
</MyElement>
<MyElement year="2006">
<Amounnt>4</Amount>
<Amounnt>7</Amount>
</MyElement>
</Root>


The problem I am having is how to loop through the MyElement elements
and get all amounts for a given unique year, then go to the next year.
In other words, I want to be able to use the year as a unique key for my
iterations.

Any help is greatly appreciated.
Thanks
 
M

Martin Honnen

hilz wrote:

<Root>
<MyElement year="2004"><Amount>10</Amount></MyElement>
<MyElement year="2004"><Amount>11</Amount></MyElement>
<MyElement year="2005"><Amount>15</Amount></MyElement>
<Root>
<MyElement year="2004">
<Amounnt>10</Amount>
<Amounnt>11</Amount>
<Amounnt>20</Amount>

The problem I am having is how to loop through the MyElement elements
and get all amounts for a given unique year, then go to the next year.
In other words, I want to be able to use the year as a unique key for my
iterations.

Then define a key and use if for grouping:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:eek:utput method="xml" indent="yes" />

<xsl:key name="elementByYear" match="MyElement" use="@year" />

<xsl:template match="Root">
<xsl:copy>
<xsl:apply-templates select="MyElement[generate-id() =
generate-id(key('elementByYear', @year)[1])]" />
</xsl:copy>
</xsl:template>

<xsl:template match="MyElement">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="key('elementByYear', @year)/Amount" />
</xsl:copy>
</xsl:template>

<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>

</xsl:stylesheet>
 
J

Joe Kesselman

<xsl:apply-templates select="MyElement[generate-id() =
generate-id(key('elementByYear', @year)[1])]" />

For those who haven't seen this trick before, it may be worth explaining...

The expression "generate-id(node1)=generate-id(node2): is a way of
testing whether node1 and node2 are the same node... often a useful
test, but one that accidentally got let out of XSLT 1.0.

In this case, we're checking it against the list of nodes keyed by the
same @year value -- specifically, against the first node in that list.
The result is that we process all the possible key values, but only the
first node for each key. This gives us a way to enumerate the keys,
which also got left out of XSLT 1.0.

Then, in the template for that node, we can retrieve and process
everything associated with that key.

Clever solution, and it has become a standard XSLT idiom... but it's
definitely not obvious to a beginner!
 
H

hilz

Joe said:
<xsl:apply-templates select="MyElement[generate-id() =
generate-id(key('elementByYear', @year)[1])]" />

For those who haven't seen this trick before, it may be worth explaining...

The expression "generate-id(node1)=generate-id(node2): is a way of
testing whether node1 and node2 are the same node... often a useful
test, but one that accidentally got let out of XSLT 1.0.

In this case, we're checking it against the list of nodes keyed by the
same @year value -- specifically, against the first node in that list.
The result is that we process all the possible key values, but only the
first node for each key. This gives us a way to enumerate the keys,
which also got left out of XSLT 1.0.

Then, in the template for that node, we can retrieve and process
everything associated with that key.

Clever solution, and it has become a standard XSLT idiom... but it's
definitely not obvious to a beginner!


Thank you Joe and Martin.
You've given me what is necessary for me to proceed.
I also found this example while searching. I guess it is the same as
what Martin suggested:

http://www.jenitennison.com/xslt/grouping/muenchian.html


thanks
 
A

Andy Dingley

Clever solution, and it has become a standard XSLT idiom... but it's
definitely not obvious to a beginner!

Is _anything_ in XSLT obvious to a beginner? I've never known a
language like it for needing a "cookbook" approach.

OTOH, I'm just starting to learn Scheme.... :cool:
 
J

Joe Kesselman

Andy said:
Is _anything_ in XSLT obvious to a beginner? I've never known a
language like it for needing a "cookbook" approach.

Depends on what languages the beginner has been exposed to in the past.
Most folks have only been taught procedural programming, and thinking in
terms of pattern-matching and recursion comes hard until you get used to it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top