xsl-list
[Top] [All Lists]

Re: Re-Organize and Sort Source Tree (Muenchian Method)

2004-09-29 12:53:56
Hi Ethan,

Here's a stylesheet that produces the desired output, by using the identity transform to copy all elements, and additional templates to match the elements you want to change:

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

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

   <!-- keys by city name -->
   <xsl:key name="cities" match="city" use="."/>
   <xsl:key name="offices" match="office" use="cities/city"/>

   <!-- 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 -->
<xsl:apply-templates select="offices/office/cities/city[count(.|key('cities',.)[1])=1]">
                   <xsl:sort select="."/>
               </xsl:apply-templates>
           </cities>
       </country>
   </xsl:template>

   <!-- new 'city' elements -->
   <xsl:template match="city">
       <city>
           <name><xsl:value-of select="."/></name>
           <offices>
               <xsl:apply-templates select="key('offices',.)">
                   <xsl:sort select="name"/>
               </xsl:apply-templates>
           </offices>
       </city>
   </xsl:template>

   <!-- new office elements -->
   <xsl:template match="office">
       <office>
           <xsl:copy-of select="@*"/>
           <!-- copy all children except 'cities' -->
           <xsl:apply-templates select="*[local-name()!='cities']"/>
       </office>
   </xsl:template>

</xsl:stylesheet>

Note however, the Muenchian grouping will only work properly if there are no cities with the same name in different countries (the 'cities' key matches all city elements throughout the document). If that's a problem you'll have to include additional
information in the key's 'use' value, something like:

<xsl:key name="cities" match="city" use="concat(ancestor::country/@name,'-',.)"/>

and then of course, use the same test in the Muenchian grouping predicate:

[count(.|key('cities',concat(ancestor::country/@name,'-',.))[1])=1]

Cheers,
Anton



<Prev in Thread] Current Thread [Next in Thread>