RE: breaking sorted material into subsections

Subject: RE: breaking sorted material into subsections
From: Oliver Becker <obecker@xxxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 18 Sep 2000 17:01:50 +0200 (MET DST)
Hi Don,

> Assuming XML looks something like this (@location left out because question
> didn't pertain to parent's @location href):
> 
> 
> <IndexEntryData>
>   <index entry = "Ca">Index1</index>
>   <index entry = "Aaaa">Index1</index>
>   <index entry = "Az">Index1</index>
>   <index entry = "Bz">Index1</index>
>   <index entry = "Abb">Index1</index>
>   <index entry = "Ba">Index1</index>
> </IndexEntryData>
> 
> This works in MSXML3 and SAXON

Do you have a different version of Saxon from mine (which is Saxon 5.4.1)?

> <xsl:template match="/">                                
>   <xsl:for-each select="//index">
>     <xsl:sort select="@entry"/>
> 
> 	<!-- if first character of @entry attrib of first preceding -->
> 	<!-- node is not equal to the context's @entry attrib -->
> 	<!-- it's a "break" on first character of @entry -->
> 	<!-- this works because we're already sorted by @entry -->
> 
>       <xsl:if test ="substring(preceding::*[1]/@entry, 1, 1) !=
> substring(@entry, 1, 1)"> 

All axes apply to the nodes in the document, not to a selected node-set.
That means, your test checks if the entry attribute of the preceding 
element in the *document* starts with a different letter.

>         <H2><xsl:value-of select="substring(@entry, 1, 1)" /></H2>
>       </xsl:if>  
> 
>       <p>
>         <a href="{../@location}">
>           <xsl:value-of select="@entry"/>
>         </a>
>       </p>
>   </xsl:for-each>
> </xsl:template>

As a result Saxon outputs (newlines added)
<H2>A</H2>
<p><a href="">Aaaa</a></p>
<H2>A</H2>
<p><a href="">Abb</a></p>
<p><a href="">Az</a></p>
<H2>B</H2>
<p><a href="">Ba</a></p>
<H2>B</H2>
<p><a href="">Bz</a></p>
<H2>C</H2>
<p><a href="">Ca</a></p>

i.e. two A headers and two B headers.

In fact it's a grouping problem: gather all indizes starting with the
same letter.
Always a good reading for this kind of problems is
http://www.jenitennison.com/xslt/grouping/muenchian.html

Adapted to Eric's problem I get

<xsl:key name="letters" match="index" use="substring(@entry,1,1)" />
<xsl:template match="IndexEntryData">
   <xsl:for-each 
        select="index[count(. | key('letters', 
                                    substring(@entry,1,1))[1]) = 1]">
      <xsl:sort select="@entry" />
      <xsl:variable name="initial" select="substring(@entry,1,1)" />
      <h2> <xsl:value-of select="$initial" /> </h2>
      <xsl:for-each select="key('letters', $initial)">
         <xsl:sort select="@entry" />
         <p> <xsl:value-of select="@entry" /> </p>
      </xsl:for-each>
   </xsl:for-each>
</xsl:template> 

Cheers,
Oliver


/-------------------------------------------------------------------\
|  ob|do        Dipl.Inf. Oliver Becker                             |
|  --+--        E-Mail: obecker@xxxxxxxxxxxxxxxxxxxxxxx             |
|  op|qo        WWW:    http://www.informatik.hu-berlin.de/~obecker |
\-------------------------------------------------------------------/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread