Re: [xsl] Identity Transform Grouping Question

Subject: Re: [xsl] Identity Transform Grouping Question
From: <ethan.kalfus@xxxxxxx>
Date: Fri, 5 Nov 2004 15:14:04 -0500
Hello All:

   Due to the vast time and energy spent by Anton Triest, a solution is at
hand.  I'm posting it here for those struggling with nested grouping levels.
Thanks very much to Anton for all of his time and help!

XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

	<!-- xmlns:exsl="http://exslt.org/common"; extension-element-prefixes="exsl"
-->

	<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
	<xsl:strip-space elements="*"/>

	<!-- keys for grouping -->
	<xsl:key name="cities" match="cities" use="city[@lang='en']"/>
	<xsl:key name="offices" match="office"
use="concat(cities/city[@lang='en'],'-',names/name[@lang='en'])"/>

	<xsl:template match="/">
		<xsl:comment> with apply-templates </xsl:comment>
		<xsl:apply-templates/>
	</xsl:template>

	<!-- identity transform: copy all elements -->
	<xsl:template match="*">
		<xsl:copy>
			<xsl:copy-of select="@*"/>
			<xsl:apply-templates/>
		</xsl:copy>
	</xsl:template>

	<!-- sort divisions by @id -->
	<xsl:template match="divisions">
		<divisions>
			<xsl:apply-templates select="division">
				<xsl:sort select="@id"/>
			</xsl:apply-templates>
		</divisions>
	</xsl:template>

	<!-- sort regions and countries by @name -->
	<xsl:template match="regions|countries">
		<xsl:copy>
			<xsl:apply-templates select="region|country">
				<xsl:sort select="@name"/>
			</xsl:apply-templates>
		</xsl:copy>
	</xsl:template>

	<!-- reorganize 'country' elements -->
	<xsl:template match="country">
		<country>
			<xsl:copy-of select="@*"/>
			<cities>
				<!-- group 'city' elements within this country -->
				<xsl:variable name="offices-in-this-country">
					<xsl:copy-of select="offices"/>
					<!-- this is a trick, to restrict all subsequent key usage to this
country only -->
				</xsl:variable>
				<xsl:apply-templates
select="msxsl:node-set($offices-in-this-country)/offices/office/cities[count(
.|key('cities',city[@lang='en'])[1])=1]">
					<xsl:sort select="city[@lang='en']"/>
				</xsl:apply-templates>
			</cities>
		</country>
	</xsl:template>

	<!-- new 'city' elements -->
	<xsl:template match="cities">
		<city name="{city[@lang='en']}">
		<!-- (uncomment this if you need multilingual city names in the output)
		<city>
			<xsl:apply-templates select="city" mode="name"/>
			-->
			<offices>
				<!-- group 'office' elements located in this city by their english name
-->
				<xsl:variable name="this-city" select="city[@lang='en']"/>
				<xsl:variable name="offices-in-this-city"
select="../../../offices/office[cities/city[@lang='en']=$this-city]"/>
				<xsl:apply-templates select="$offices-in-this-city
					[count(.|key('offices',
concat(cities/city[@lang='en'],'-',names/name[@lang='en']))[1])=1]">
					<xsl:sort select="names/name[@lang='en']"/>
				</xsl:apply-templates>
			</offices>
		</city>
	</xsl:template>

	<!-- new city name elements -->
	<xsl:template match="city" mode="name">
		<name>
			<xsl:copy-of select="@*"/>
			<xsl:value-of select="."/>
		</name>
	</xsl:template>

	<!-- new office elements -->
	<xsl:template match="office">
		<office>
			<xsl:apply-templates select="names/name"/>
			<!-- add locations for each office with this name -->
			<xsl:apply-templates select="key('offices',
				concat(cities/city[@lang='en'],'-',names/name[@lang='en']))"
mode="location">
				<xsl:sort select="address"/>
			</xsl:apply-templates>
		</office>
	</xsl:template>

	<!-- new location elements -->
	<xsl:template match="office" mode="location">
		<location>
			<xsl:copy-of select="@*"/>
			<xsl:apply-templates select="address|phone"/>
		</location>
	</xsl:template>

</xsl:stylesheet>


Sample XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="locations-3.xsl" ?>
<locations version="1.0">
   <divisions>
      <division id="B">
         <regions>
            <region name="americas">
               <countries>
                  <country name="United States">
                     <offices>
                        <office id="HOb">
                           <names>
                              <name lang='en'>Home Office</name>
                              <name lang='fr'>Home Office (French)</name>
                              <name lang='de'>Home Office (German)</name>
                           </names>
                           <address>
 		      <line>division B</line>
                              <line>P.O. Box 1234</line>
                              <line>New York, NY  11111</line>
                           </address>
                           <cities>
                              <city lang='en'>New York</city>
                              <city lang='fr'>New York (French)</city>
                              <city lang='de'>New York (German)</city>
                           </cities>
                           <phone>(212) 123-4567</phone>
                        </office>
                        <office id="BR1b">
                           <names>
                              <name lang='en'>Branch 1</name>
                              <name lang='fr'>Branch 1 (French)</name>
                              <name lang='de'>Branch 1 (German)</name>
                           </names>
                           <address>
		      <line>division B</line>
                              <line>999 Main Street</line>
                              <line>Suite 1200</line>
                              <line>Miami, FL  22222</line>
                           </address>
                           <cities>
                              <city lang='en'>Miami</city>
                              <city lang='fr'>Miami (French)</city>
                              <city lang='de'>Miami (German)</city>
                           </cities>
                           <phone>777-7777</phone>
                        </office>
                     </offices>
                  </country>
                  <country name="Canada">
                     <offices>
                        <office id="Branch 2b">
                           <names>
                              <name lang='en'>Canadian Branch</name>
                              <name lang='fr'>Canadian Branch (French)</name>
                              <name lang='de'>Canadian Branch (German)</name>
                           </names>
                           <address>
		      <line>division B</line>
                              <line>1 Prince Edward Boulevard</line>
                              <line>5th Floor</line>
                              <line>Room 10</line>
                              <line>Calgary, Alberta</line>
                           </address>
                           <cities>
                              <city lang='en'>Calgary</city>
                              <city lang='fr'>Calgary (French)</city>
                              <city lang='de'>Calgary (German)</city>
                           </cities>
                           <phone>(888) 888-8888</phone>
                        </office>
                     </offices>
                  </country>
               </countries>
            </region>
            <region name="pacific">
               <countries>
                  <country name="China">
                     <offices>
                        <office id="BR5b">
                           <names>
                              <name lang='en'>Branch 5</name>
                              <name lang='fr'>Branch 5 (French)</name>
                              <name lang='de'>Branch 5 (German)</name>
                           </names>
                           <address>
		      <line>division B</line>
                              <line>China World Tower 1</line>
                              <line>1 Jian Guo Men Wai Avenue</line>
                              <line>Beijing</line>
                           </address>
                           <cities>
                              <city lang='en'>Beijing</city>
                              <city lang='fr'>Beijing (French)</city>
                              <city lang='de'>Beijing (German)</city>
                           </cities>
                           <phone/>
                        </office>
                     </offices>
                  </country>
               </countries>
            </region>
         </regions>
      </division>
      <division id="A">
         <regions>
            <region name="europe">
               <countries>
                  <country name="Germany">
                     <offices>
                        <office id="BR3a">
                           <names>
                              <name lang='en'>Branch 3</name>
                              <name lang='fr'>Branch 3 (French)</name>
                              <name lang='de'>Branch 3 (German)</name>
                           </names>
                           <address>
		      <line>division A</line>
                              <line>P.O. Box 1210</line>
                              <line>Frankfurt, Germany</line>
                           </address>
                           <cities>
                              <city lang='en'>Frankfurt</city>
                              <city lang='fr'>Frankfurt (French)</city>
                              <city lang='de'>Frankfurt (German)</city>
                           </cities>
                           <phone>+49-55-5555 5555</phone>
                        </office>
                     </offices>
                  </country>
                  <country name="England">
                     <offices>
                        <office id="BR6a">
                           <names>
                              <name lang='en'>Branch 4</name>
                              <name lang='fr'>Branch 4 (French)</name>
                              <name lang='de'>Branch 4 (German)</name>
                           </names>
                           <address>
		      <line>division A</line>
                              <line>26 Abbey Lane</line>
                              <line>New Castle</line>
                           </address>
                           <cities>
                              <city lang='en'>New Castle</city>
                              <city lang='fr'>New Castle (French)</city>
                              <city lang='de'>New Castle (German)</city>
                          </cities>
                           <phone>+44-22-2222 2222</phone>
                        </office>
                        <office id="BR5a">
                           <names>
                              <name lang='en'>Branch 4</name>
                               <name lang='fr'>Branch 4 (French)</name>
                              <name lang='de'>Branch 4 (German)</name>
                          </names>
                           <address>
		      <line>division A</line>
                              <line>7 Kings Highway</line>
                              <line>London</line>
                           </address>
                           <cities>
                              <city lang='en'>London</city>
                              <city lang='fr'>London (French)</city>
                              <city lang='de'>London (German)</city>
                           </cities>
                           <phone>+44-99-9999 9999</phone>
                        </office>
                        <office id="BR8a">
                           <names>
                              <name lang='en'>AAAABranch 4</name>
                              <name lang='fr'>AAAABranch 4 (French)</name>
                              <name lang='de'>AAAABranch 4 (German)</name>
                           </names>
                           <address>
		      <line>division A</line>
                              <line>44 Surrey Street</line>
                              <line>London</line>
                           </address>
                           <cities>
                              <city lang='en'>London</city>
                              <city lang='fr'>London (French)</city>
                              <city lang='de'>London (German)</city>
                           </cities>
                           <phone>+44-55-555 5555</phone>
                        </office>
                        <office id="BR7a">
                           <names>
                              <name lang='en'>Branch 4</name>
                              <name lang='fr'>Branch 4 (French)</name>
                              <name lang='de'>Branch 4 (German)</name>
                           </names>
                           <address>
		      <line>division A</line>
                              <line>22 Abbey Lane</line>
                              <line>London</line>
                           </address>
                           <cities>
                              <city lang='en'>London</city>
                              <city lang='fr'>London (French)</city>
                              <city lang='de'>London (German)</city>
                           </cities>
                           <phone>+44-55-555 5555</phone>
                        </office>
                     </offices>
                  </country>
               </countries>
            </region>
            <region name="americas">
               <countries>
                  <country name="United States">
                     <offices>
                        <office id="HOa">
                           <names>
                              <name lang='en'>Home Office</name>
                              <name lang='fr'>Home Office (French)</name>
                              <name lang='de'>Home Office (German)</name>
                           </names>
                           <address>
		      <line>division A</line>
                              <line>P.O. Box 1234</line>
                              <line>New York, NY  11111</line>
                           </address>
                           <cities>
                              <city lang='en'>New York</city>
                              <city lang='fr'>New York (French)</city>
                              <city lang='de'>New York (German)</city>
                           </cities>
                           <phone>(212) 123-4567</phone>
                        </office>
                        <office id="BR1a">
                           <names>
                              <name lang='en'>Branch 1</name>
                           </names>
                           <address>
 		      <line>division A</line>
                              <line>999 Main Street</line>
                              <line>Suite 1200</line>
                              <line>Miami, FL  22222</line>
                           </address>
                           <cities>
                              <city lang='en'>Miami</city>
                              <city lang='fr'>Miami (French)</city>
                              <city lang='de'>Miami (German)</city>
                           </cities>
                           <phone>777-7777</phone>
                        </office>
                     </offices>
                  </country>
                  <country name="Canada">
                     <offices>
                        <office id="Branch 2a">
                           <names>
                              <name lang='en'>Canadian Branch</name>
                              <name lang='fr'>Canadian Branch (French)</name>
                              <name lang='de'>Canadian Branch (German)</name>
                           </names>
                           <address>
		      <line>division A</line>
                              <line>1 Prince Edward Boulevard</line>
                              <line>5th Floor</line>
                              <line>Room 10</line>
                              <line>Calgary, Alberta</line>
                           </address>
                           <cities>
                              <city lang='en'>Calgary</city>
                              <city lang='fr'>Calgary (French)</city>
                              <city lang='de'>Calgary (German)</city>
                           </cities>
                           <phone>(888) 888-8888</phone>
                        </office>
                     </offices>
                  </country>
               </countries>
            </region>
         </regions>
      </division>
   </divisions>
</locations>

Visit our website at http://www.ubs.com

This message contains confidential information and is intended only
for the individual named.  If you are not the named addressee you
should not disseminate, distribute or copy this e-mail.  Please
notify the sender immediately by e-mail if you have received this
e-mail by mistake and delete this e-mail from your system.

E-mail transmission cannot be guaranteed to be secure or error-free
as information could be intercepted, corrupted, lost, destroyed,
arrive late or incomplete, or contain viruses.  The sender therefore
does not accept liability for any errors or omissions in the contents
of this message which arise as a result of e-mail transmission.  If
verification is required please request a hard-copy version.  This
message is provided for informational purposes and should not be
construed as a solicitation or offer to buy or sell any securities or
related financial instruments.

Current Thread