RE: [xsl] Grouping examples make my head spin

Subject: RE: [xsl] Grouping examples make my head spin
From: "Macaulay,Malcolm (US)" <Malcolm.Macaulay2@xxxxxxxxx>
Date: Mon, 5 Aug 2002 16:52:32 -0500
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@xxxxxxxxxx]
Sent: Monday, August 05, 2002 4:10 PM
To: XSL-List@xxxxxxxxxxxxxxxxxxxxxx
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&apos;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@xxxxxxxxxx - 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


Current Thread