RE: [xsl] Group by letter

Subject: RE: [xsl] Group by letter
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Sun, 27 Jan 2008 22:05:52 -0000
It looks as if you are unfamiliar with the general approach to grouping in
XSLT.

In XSLT 2.0, use <xsl:for-each-group select="*"
group-by="upper-case(substring(dt,1,1))">.

If you have to use XSLT 1.0, use Muenchian grouping as described at
http://www.jenitennison.com/xslt/grouping or in most XSLT textbooks.

Michael Kay
http://www.saxonica.com/ 

> -----Original Message-----
> From: Rick Quatro [mailto:frameexpert@xxxxxxxxxxxx] 
> Sent: 27 January 2008 21:59
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] Group by letter
> 
> Hello All,
> 
> Here is an example of my input:
> 
> <?xml version="1.0" encoding="utf-8"?>
> <reference>
>   <refbody>
>     <section>
>       <title>Show Author ID</title>
>       <p id="Field_ShowAuthorID">Show Author ID</p>
>       <p id="Desc_ShowAuthorID">Setting that indicates if the 
> ID...</p>
>       <p id="AppTo_ShowAuthorID">Review Definitions</p>
>       <p id="Hdr_ShowAuthorID">Author Settings</p>
>     </section>
>     <section>
>       <title>Author Job Title</title>
>       <p id="Field_ShowAuthorJobTitle">Author Job Title</p>
>       <p id="Desc_ShowAuthorJobTitle">Setting that indicates 
> if the job title...</p>
>       <p id="AppTo_ShowAuthorJobTitle">Review Definitions, 
> Section Item</p>
>       <p id="Hdr_ShowAuthorJobTitle">Author Settings</p>
>     </section>
>     <section>
>       <title>Author Description</title>
>       <p id="Field_AuthorDescription">Author Description</p>
>       <p id="Desc_AuthorDescription">Description of the 
> performance review defined...</p>
>       <p id="AppTo_AuthorDescription">Review Definitions, 
> Section Item</p>
>       <p id="Hdr_AuthorDescription">Author Settings</p>
>     </section>
>   </refbody>
> </reference>
> 
> My stylesheet successfully sorts by <title> and outputs a 
> simple glossary like this:
> 
> <?xml version="1.0" encoding="utf-16"?>
> <definitions>
>   <dlentry>
>     <dt>Author Description</dt>
>     <dd>Description of the performance review defined...</dd>
>   </dlentry>
>   <dlentry>
>     <dt>Author Job Title</dt>
>     <dd>Setting that indicates if the job title...</dd>
>   </dlentry>
>   <dlentry>
>     <dt>Show Author ID</dt>
>     <dd>Setting that indicates if the ID...</dd>
>   </dlentry>
> </definitions>
> 
> I need to go one step further and group the <dlentry> 
> elements by the first character (case-insensitive) of the 
> <dt> element, which is originally the first <p> element in 
> the source document. So, the desired output would be:
> 
> <?xml version="1.0" encoding="utf-16"?>
> <definitions>
>   <dl title="A">
>     <dlentry>
>       <dt>Author Description</dt>
>       <dd>Description of the performance review defined...</dd>
>     </dlentry>
>     <dlentry>
>       <dt>Author Job Title</dt>
>       <dd>Setting that indicates if the job title...</dd>
>     </dlentry>
>   </dl>
>   <dl title="S">
>     <dlentry>
>       <dt>Show Author ID</dt>
>       <dd>Setting that indicates if the ID...</dd>
>     </dlentry>
>   </dl>
> </definitions>
> 
> Here is my working stylesheet:
> 
> <?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" />
> 
> <xsl:template match="reference">
>   <definitions>
>     <xsl:apply-templates select="refbody" />
>   </definitions>
> </xsl:template>
> 
> <xsl:template match="refbody">
>   <xsl:apply-templates select="section">
>     <xsl:sort select="title" />
>   </xsl:apply-templates>
> </xsl:template>
> 
> <xsl:template match="section">
>   <dlentry>
>     <xsl:apply-templates select="p" />
>   </dlentry>
> </xsl:template>
> 
> <xsl:template match="p[position()=1]">
>   <dt>
>     <xsl:copy-of select="text()|*" />
>   </dt>
> </xsl:template>
> 
> <xsl:template match="p[position()=2]">
>   <dd>
>     <xsl:copy-of select="text()|*" />
>   </dd>
> </xsl:template>
> 
> <xsl:template match="p"/>
> 
> </xsl:stylesheet>
> 
> I think I have to add a predicate to this line to find out 
> when a <p> has a different first character than the previous one did:
> 
> <xsl:template match="p[position()=1]">
> 
> but I am having trouble figuring out what I need. Any help or 
> pointers would be appreciated. Thank you very much.
> 
> Rick Quatro
> Carmen Publishing
> 585-659-8267
> www.frameexpert.com

Current Thread