Home. 
.

transparent

transparent

transparent

Altova Mailing List Archives


Howto: Multiple Groups (Muenchian Method)

From: anyware@-----------.---------.---
To: NULL
Date: 11/1/2004 12:00:00 PM
Hi,

  I have an xslt that does most of what I need to do.  It performs an 
identity transform on the source tree, grouping and sorting elements as 
appropriate (see NOTES below).  I am having trouble getting the the nested 
grouping correct.  I am using the Muenchian method for the grouping and 
for-each rather than templates -- I want to keep the for-each approach since 
it seems to be close to working, just want to add the final piece to the 
puzzle.  

  Some of the transform was provided to me by someone on this site and 
performs well.  It relies on the msxml extension function "node-set()", which 
is acceptable.  The xslt must be compatible with xslt 1.0 running under msxml 
3.

  The source tree looks like the following (NOTE: very simplified version of 
actual 
source -- please see NOTES below):

<office_locations>
<divisions>
   <division id="A">
      <regions>
         <region name="europe">
            <countries>
               <country name="England">
                  <offices>
                     <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>
      </regions>
   </division>
</divisions>
</office_locations>

The result tree should look like this:

<office_locations>
<divisions>
   <division id="A">
      <regions>
         <region name="europe">
            <countries>
               <country name="England">
                  <cities>
                     <city>
                        <name>London</name>
                        <offices>
                           <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>
                              <location>
                                 <address>
                                    <line>division A</line>
                                    <line>44 Surrey Street</line>
                                    <line>London</line>
                                 </address>
                                 <phone>+44-55-555 5555</phone>
                              </location> 
                          </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>
                             <location id="BR7a">
                                <address>
                                   <line>division A</line>
                                   <line>22 Abbey Lane</line>
                                   <line>London</line>
                                </address>
                                <phone>+44-55-555 5555</phone>
                             </location>	   
                             <location id="BR5a">
                                <address>
                                   <line>division A</line>
                                   <line>7 Kings Highway</line>
                                   <line>London</line>
                                </address>
                                <phone>+44-99-9999 9999</phone>
                             </location>
                          </office>
                       </offices>
                    </city>
                 </cities>
              </country>
            </countries>
         </region>
      </regions>
   </division>
</divisions>
</office_locations>

My current xslt looks like this:

<?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">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:key name="by-city" match="temp/office/cities/city[@lang='en']" use="."/>
<xsl:template match="/">
   <locations>
      <divisions>
         <xsl:for-each select="office_locations/divisions/division">
            <xsl:sort select="@id"/>
            <division id="{@id}">
               <regions>
                  <xsl:for-each select="regions/region">
                     <xsl:sort select="@name"/>
                     <region name="{@name}">
                        <countries>
                           <xsl:for-each select="countries/country">
                              <xsl:sort select="@name"/>
                              <country name="{@name}">
                                 <xsl:variable name="rtf">
                                    <temp>
                                       <xsl:copy-of select="offices/office"/>
                                    </temp>
                                 </xsl:variable>
                                 <xsl:for-each 
select="msxsl:node-set($rtf)/temp/office/cities/city[@lang='en' and 
generate-id(.) = generate-id(key('by-city', .)[1])]">
                                    <xsl:sort select="." />
                                          <cities>
                                          <city>
                                               <name><xsl:value-of 
select="." /></name>                       
                                               <offices>
                                                 <xsl:for-each 
select="key('by-city', .)">   
                                                      <xsl:sort 
select="../../names/name[@lang='en']" />
													  <xsl:sort select="../preceding-sibling::address" />
                                                      <office 
id="{../../@id}">
                                                         <xsl:copy-of 
select="../preceding-sibling::names" />
                                                         <xsl:copy-of 
select="../preceding-sibling::address" />
                                                         <xsl:copy-of 
select="../following-sibling::phone" />
                                                      </office>
                                                 </xsl:for-each>
                                               </offices>
                                            </city>
                                          </cities>
                                 </xsl:for-each>
                              </country>
                           </xsl:for-each>
                        </countries>
                     </region>
                  </xsl:for-each>
               </regions>
            </division>
         </xsl:for-each>
      </divisions>
   </locations>
</xsl:template>
</xsl:stylesheet>


NOTES:
1.  The result tree only needs the English translation of <city> (e.g. 
city[@lang='en']), but needs all translations of <office>.

2.  Since an office with the same name can appear in more than one city in 
more than one country in more than one region in more than one division, 
nodes need to be grouped to account for this.  Currently, the xslt groups 
offices by city (according to the English translation, e.g. @lang='en'); the 
missing piece is additionally grouping same-named offices (e.g. 
names/name[@lang='en']) under their associated <city> parent node.  What I 
would like is to wrap each <office> node with a new parent -- "location".  If 
there is more than one office with the same name in the same city (and in the 
same division/region/country), then only one <office> node should be created 
(and with just one instance of its corresponding <names> child node), with 
separate child <location> nodes beneath it for each office of the same name.  

3.  The result tree needs to be sorted in the following order (from least 
granular to most granular): division/@id, region/@name, country/@name, 
city[@lang='en'], office/names/name[@lang='en'], address.

Thanks for any help!


transparent
Print
Mail
Like It
Disclaimer
.

These Archives are provided for informational purposes only and have been generated directly from the Altova mailing list archive system and are comprised of the lists set forth on www.altova.com/list/index.html. Therefore, Altova does not warrant or guarantee the accuracy, reliability, completeness, usefulness, non-infringement of intellectual property rights, or quality of any content on the Altova Mailing List Archive(s), regardless of who originates that content. You expressly understand and agree that you bear all risks associated with using or relying on that content. Altova will not be liable or responsible in any way for any content posted including, but not limited to, any errors or omissions in content, or for any losses or damage of any kind incurred as a result of the use of or reliance on any content. This disclaimer and limitation on liability is in addition to the disclaimers and limitations contained in the Website Terms of Use and elsewhere on the site.

.
.

transparent

transparent