This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
RE: Grouping examples make my head spin
- From: "Macaulay,Malcolm (US)" <Malcolm dot Macaulay2 at cnare dot com>
- To: <xsl-list at lists dot mulberrytech dot com>
- Cc: <cknell at onebox dot com>
- Date: Mon, 5 Aug 2002 16:52:32 -0500
- Subject: RE: [xsl] Grouping examples make my head spin
- Reply-to: xsl-list at lists dot mulberrytech dot com
Hi Charles,
Below is a sample XSLT which does (hopefully) something close to what you want. I've put comments into the XSLT to try to explain what is going on.
I used the Muenchian method to get the unique @org's - take a look at Jeni T's good website (http://www.jenitennison.com/xslt/grouping/muenchian.html) and the archives of this list for more info.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- Create keyed index of contract/@org's-->
<xsl:key name="orgsByOrg" match="/contractors/contractor/contract/@org" use="."/>
<xsl:template match="/">
<table border="1">
<tr>
<th>@org</th>
<th>contractor names</th>
</tr>
<!-- loop through all the UNIQUE values of @org 9unique ones by Muenchian method -->
<xsl:for-each select="contractors/contractor/contract/@org[generate-id(.)=generate-id(key('orgsByOrg',.)[1])]">
<!--
Store @org ID values for use below-->
<xsl:variable name="orgID" select="."/>
<tr>
<!-- write org ID-->
<td>
<xsl:value-of select="."/>
</td>
<td>
<!-- Build table of names of all contractors who participate on contract where @org = the current @org-->
<table border="1">
<xsl:for-each select="/contractors/contractor[contract/@org = $orgID]">
<tr>
<td>
<xsl:value-of select="@name"/>
</td>
</tr>
</xsl:for-each>
</table>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Hope that helps.
cheers
Malcolm
-----Original Message-----
From: Charles Knell [mailto:cknell@onebox.com]
Sent: Monday, August 05, 2002 4:10 PM
To: XSL-List@lists.mulberrytech.com
Subject: [xsl] Grouping examples make my head spin
I've just started doing my first XML grouping attempt. I've been looking
over three books all day, but the solution keeps eluding my grasp. I
think my problem is that all the examples presented are based on non-hierarchical
elements, and I don't have the knowledge to abstract the principles from
them to apply it to my situation.
examples:
from XSLT Programmer's Refernce 2nd Edition, pg.623:
<cities>
<city name="Paris" country="France" />
<city name="Roma" country="Italia" />
<city name="Nice" country="France" />
...
<cities>
or from XSLT and XPath on the Edge, pg 198:
<transaction date="2001-03-01" type="DD" payee="TV License">8.91<transaction>
<transaction date="2001-03-01" type="DD" payee="British Gas">22.00<transaction>
<transaction date="2001-03-03" type="CR" payee="Client">400.00<transaction>
...
My data file is hierachical:
<contractors>
<contractor id="x" name="A">
<contract org="1596" contract-id="89" name="SuperDuperIII">
<contractType>System</contractType>
<deliverable>Application Development</deliverable>
</contract>
<contract org="98" contract-id="75" name="SixtySix">
<contractType>Non-system</contractType>
<deliverable>Neon Routers</deliverable>
</contract>
</contractor>
<contractor id="16" name="W">
<contract org="1596" contract-id="1365" name="Bosco">
<contractType>System</contractType>
<deliverable>Application Development</deliverable>
</contract>
<contract org="98" contract-id="258" name="Xanadu">
<contractType>System</contractType>
<deliverable>Application Development</deliverable>
</contract>
</contractor>
</contractors>
I want to outpt HTML. I want each distinct value for /contractors/contractor/contract/@org
to be output exactly once, with a list (format irrelevant for the purposes
of the exercise) of /contractors/contractor/@name below that, one for
each contractor which has a contract with /contractors/contractor/contract/@org.
I think what I need to do is get a list of unique values for /contractors/contractor/contract/@org
and then loop through all instances of /contractors/contractor, checking
each value of contract/@org. If I find a new value, I want to emit an
HTML div element with that value, if the value has already been encountered,
I want to emit an HTML div element containing the value of /contractors/contractor/@name.
I have tried this template:
<xsl:template name="byPO" match="*">
<xsl:for-each select="/contractors/contractor/contract">
<div>Contract Org: <xsl:value-of select="@org" /></div>
<div>Immediate preceeding sibling's contract Org: <xsl:value-of
select="preceding-sibling[1]/@org" /></div>
</xsl:for-each>
</xsl:template>
but the output shows me that no /contractors/contractor/contract has
an immediately preceeding sibling, which I can see is not true, so there
for I am missing something in my understanding of <xsl:value-of select="preceding-sibling[1]/@org"
/>.
As usual, all help gratefully received.
Thanks.
--
Charles Knell
cknell@onebox.com - email
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list