[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: XSLT/XPath Question (Grouping Authors by First Ch

Subject: Re: XSLT/XPath Question (Grouping Authors by First Character of Last Name)
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Sat, 3 Mar 2007 19:24:48 -0800
Re:  XSLT/XPath Question (Grouping Authors by First  Ch
Perfect.  Thanks.  Just out of curiosity, is this possible
(practical?) in XSLT 1.0?

Yes and yes -- read about the Muenchian method for grouping.


Actually, this reminds me that six years ago I published a snippet in
topxml.com solving exactly your problem in XSLT 1.0:


http://www.topxml.com/code/default.asp?p=3&id=v20010129150851




--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play


On 3/3/07, Kevin Grover <kevin@xxxxxxxxxxxxxxx> wrote:
Perfect.  Thanks.  Just out of curiosity, is this possible
(practical?) in XSLT 1.0?

On 3/3/07, Dimitre Novatchev <dnovatchev@xxxxxxxxx> wrote:
> You are not using XSLT 2.0 to its full potential.
>
> The solution is as easy as this:
>
> <xsl:stylesheet version="2.0"
>  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>  >
>   <xsl:output method="text"/>
>
>  <xsl:template match="/">
>    <xsl:for-each-group select="*/author"
>      group-by="substring(name/@file-as,1,1)"
>     >
>      <xsl:text>&#xA;&#xA;</xsl:text>
>      <xsl:value-of select="current-grouping-key()"/>
>      <xsl:text>&#xA;</xsl:text>
>
>      <xsl:for-each select="current-group()">
>        <xsl:value-of select="name/@file-as"/>
>        <xsl:text>&#xA;</xsl:text>
>      </xsl:for-each>
>    </xsl:for-each-group>
>  </xsl:template>
> </xsl:stylesheet>
>
> and  when applied on the provided xml document it produces the wanted result:
>
>
>
> A
> Adams, Douglas
> Anderson, Kevin J.
> Anthony, Piers
> Archer, Jeffrey
>
>
> B
> Baldacci, David
> Ball, Margaret
> Bradley, Marion Zimmer
>
>
> C
> Carcaterra, Lorenzo
> Card, Orson Scott
> Chalker, Jack L.
>
>
> D
> Dahl, Roald
> Daley, Brian
> Dann, Jack
>
>
>
> --
> Cheers,
> Dimitre Novatchev
> ---------------------------------------
> Truly great madness cannot be achieved without significant intelligence.
> ---------------------------------------
> To invent, you need a good imagination and a pile of junk
> -------------------------------------
> You've achieved success in your field when you don't know whether what
> you're doing is work or play
>
>
>
>
> On 3/3/07, Kevin Grover <kevin@xxxxxxxxxxxxxxx> wrote:
> > I have an XSLT/XPath Question that I've been beating my head against
> > for a while.
> >
> > I have a list of authors with a name element and a file-as attribute
> > (XPATH: /booklist/author/name/@file-as).  I currently build a Table of
> > Contents sorted by the author/name/@file-as attribute.  That works OK.
> >  I want to add further markup (by putting authors in groups by the
> > first character of their last name).
> >
> > I can get the first character of the last name, I've even created a
> > key that allows me to access the nodes of authors by the first
> > character in the last name (see the commented out section of the b.xsl
> > file included below).  However, I can not figure out how to get a list
> > of distinct characters (from the last names) so that I can iterate
> > over them and generate my list.
> >
> > Here are stripped down example source files:
> >
> > Exmaple author file: (file a.xml)
> >
> > <?xml version="1.0" encoding="UTF-8"?>
> > <booklist>
> >   <author>
> >      <name file-as="Adams, Douglas">Douglas Adams</name>
> >   </author>
> >   <author>
> >      <name file-as="Anderson, Kevin J.">Kevin J. Anderson</name>
> >   </author>
> >   <author>
> >      <name file-as="Anthony, Piers">Piers Anthony</name>
> >   </author>
> >   <author>
> >      <name file-as="Archer, Jeffrey">Jeffrey Archer</name>
> >   </author>
> >   <author>
> >      <name file-as="Baldacci, David">David Baldacci</name>
> >   </author>
> >   <author>
> >      <name file-as="Ball, Margaret">Margaret Ball</name>
> >   </author>
> >   <author>
> >      <name file-as="Bradley, Marion Zimmer">Marion Zimmer Bradley</name>
> >   </author>
> >   <author>
> >      <name file-as="Carcaterra, Lorenzo">Lorenzo Carcaterra</name>
> >   </author>
> >   <author>
> >      <name file-as="Card, Orson Scott">Orson Scott Card</name>
> >   </author>
> >   <author>
> >      <name file-as="Chalker, Jack L.">Jack L. Chalker</name>
> >   </author>
> >   <author>
> >      <name file-as="Dahl, Roald">Roald Dahl</name>
> >   </author>
> >   <author>
> >      <name file-as="Daley, Brian">Brian Daley</name>
> >   </author>
> >   <author>
> >      <name file-as="Dann, Jack">Jack Dann</name>
> >   </author>
> > </booklist>
> >
> >
> > I can extract the authors and generate a table of contents with the
> > following XSLT: (b.xsl)
> >
> > <?xml version="1.0"?>
> > <xsl:stylesheet version="1.0"
> >                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> >                >
> >    <xsl:output method="xml"/>
> >    <xsl:output indent="yes"/>
> >    <xsl:strip-space elements="*"/>
> >
> >    <xsl:key name="alet" match="//author" use="substring(name/@file-as,1,1)"/>
> >
> >    <xsl:template match="/booklist">
> >        <xsl:call-template name="gen-toc"/>
> >    </xsl:template>
> >
> >    <!-- Generate Table of Contents -->
> >    <xsl:template name="gen-toc">
> >      <div id="toc" class="toc">
> > <!--
> >      <h1>Test</h1>
> >      <ul>
> >      <xsl:for-each select="key('alet','A')">
> >        <li><xsl:value-of select="name/@file-as"/></li>
> >      </xsl:for-each>
> >      </ul>
> > -->
> >      <h1>Table of Contents (by Author)</h1>
> >      <ul>
> >      <xsl:for-each select="//author/name">
> >        <xsl:sort select="@file-as"/>
> >        <li><a href="#{generate-id(..)}"><xsl:value-of
> > select="@file-as"/></a></li>
> >      </xsl:for-each>
> >      </ul>
> >      </div>
> >    </xsl:template>
> >
> > </xsl:stylesheet>
> >
> >
> > This works.  It generates this: (out.xml)
> >
> > <?xml version="1.0"?>
> > <div id="toc" class="toc">
> >  <h1>Table of Contents (by Author)</h1>
> >  <ul>
> >    <li>
> >      <a href="#id91524">Adams, Douglas</a>
> >    </li>
> >    <li>
> >      <a href="#id91570">Anderson, Kevin J.</a>
> >    </li>
> >    <li>
> >      <a href="#id91578">Anthony, Piers</a>
> >    </li>
> >    <li>
> >      <a href="#id91588">Archer, Jeffrey</a>
> >    </li>
> >    <li>
> >      <a href="#id91597">Baldacci, David</a>
> >    </li>
> >    <li>
> >      <a href="#id91607">Ball, Margaret</a>
> >    </li>
> >    <li>
> >      <a href="#id91617">Bradley, Marion Zimmer</a>
> >    </li>
> >    <li>
> >      <a href="#id91627">Carcaterra, Lorenzo</a>
> >    </li>
> >    <li>
> >      <a href="#id93622">Card, Orson Scott</a>
> >    </li>
> >    <li>
> >      <a href="#id93633">Chalker, Jack L.</a>
> >    </li>
> >    <li>
> >      <a href="#id93643">Dahl, Roald</a>
> >    </li>
> >    <li>
> >      <a href="#id93653">Daley, Brian</a>
> >    </li>
> >    <li>
> >      <a href="#id93663">Dann, Jack</a>
> >    </li>
> >  </ul>
> > </div>
> >
> >
> > I want to change that so that I have the authors in subsections, with
> > the first letter of their last names as the the main entry, like so
> >
> >        A
> >                //author/name/@file-as[.=='A']
> >        B
> >                //author/name/@file-as[.=='B']
> >        etc..
> >
> > Like this output: (out-desired.xml)
> >
> > [This was hand edited, I have not yet figured out how to automatically
> > generate it.]
> >
> > <?xml version="1.0"?>
> > <div id="toc" class="toc">
> >  <h1>Table of Contents (by Author)</h1>
> >  <ul>
> >    <li>
> >      <a name="A">A</a>
> >      <ul>
> >        <li>
> >          <a href="#id91524">Adams, Douglas</a>
> >        </li>
> >        <li>
> >          <a href="#id91570">Anderson, Kevin J.</a>
> >        </li>
> >        <li>
> >          <a href="#id91578">Anthony, Piers</a>
> >        </li>
> >        <li>
> >          <a href="#id91588">Archer, Jeffrey</a>
> >        </li>
> >        <li>
> >          <a href="#id91597">Baldacci, David</a>
> >        </li>
> >      </ul>
> >    </li>
> >    <li>
> >      <a name="B">B</a>
> >      <ul>
> >        <li>
> >          <a href="#id91607">Ball, Margaret</a>
> >        </li>
> >        <li>
> >          <a href="#id91617">Bradley, Marion Zimmer</a>
> >        </li>
> >      </ul>
> >    </li>
> >    <li>
> >      <a name="C">C</a>
> >      <ul>
> >        <li>
> >          <a href="#id91627">Carcaterra, Lorenzo</a>
> >        </li>
> >        <li>
> >          <a href="#id93622">Card, Orson Scott</a>
> >        </li>
> >        <li>
> >          <a href="#id93633">Chalker, Jack L.</a>
> >        </li>
> >      </ul>
> >    </li>
> >    <li>
> >      <a name="D">D</a>
> >      <ul>
> >        <li>
> >          <a href="#id93643">Dahl, Roald</a>
> >        </li>
> >        <li>
> >          <a href="#id93653">Daley, Brian</a>
> >        </li>
> >        <li>
> >          <a href="#id93663">Dann, Jack</a>
> >        </li>
> >      </ul>
> >    </li>
> >  </ul>
> > </div>
> >
> >
> > I've tried some XPath 2 stuff and XQuery.  I can get a list of first
> > letters using XQuery (and thus XPath 2)
> >
> > For example: (file fl.xq)
> >
> > for $a in //author/name/substring(@file-as,1,1)
> > return
> >  <c>{$a}</c>
> >
> >
> > Generates a list of the characters of the last name (although not unique).
> >
> > I tried embedding something like the above "for $a in.." into an XSLT
> > 2.0 stylesheet, and assign it to a variable, but I get an error from
> > saxon when I tried it.
> >
> > Something like this is desired.... (with UNIQUE-SET-OF-FIRST-LETTERS)
> > replaced with something that works.  I set this to XSLT 2, and tried
> > "$letters//l" in place of that place-holder text
> > (UNIQUE-SET-OF-FIRST-LETTERS).  It generated the Letter items A B C
> > .., but all of the sub <ul>s where empty.
> >
> > <?xml version="1.0"?>
> > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
> >  <xsl:output method="xml"/>
> >  <xsl:output indent="yes"/>
> >  <xsl:strip-space elements="*"/>
> >
> >  <xsl:key name="alet" match="//author" use="substring(name/@file-as,1,1)"/>
> >
> > <!--
> >  <xsl:variable name="letters">
> >    <l>A</l>
> >    <l>B</l>
> >    <l>C</l>
> >    <l>D</l>
> >    <l>E</l>
> >  </xsl:variable>
> > -->
> >  <xsl:template match="/booklist">
> >    <xsl:call-template name="gen-toc"/>
> >  </xsl:template>
> >
> >  <!-- Generate Table of Contents -->
> >  <xsl:template name="gen-toc">
> >    <div id="toc" class="toc">
> >      <h1>Table of Contents (by Author)</h1>
> >      <ul>
> >        <xsl:for-each select="UNIQUE-SET-OF-FIRST-LETTERS">
> >          <xsl:variable name="lc" select="."/>
> >          <li>
> >            <a>
> >              <xsl:attribute name="name" select="$lc"/>
> >              <xsl:value-of select="$lc"/>
> >            </a>
> >            <ul>
> >              <xsl:for-each select="key('alet',$lc)">
> >                <xsl:sort select="name/@file-as"/>
> >                <li>
> >                  <a href="#{generate-id(.)}">
> >                    <xsl:value-of select="name/@file-as"/>
> >                  </a>
> >                </li>
> >              </xsl:for-each>
> >            </ul>
> >          </li>
> >        </xsl:for-each>
> >      </ul>
> >    </div>
> >  </xsl:template>
> > </xsl:stylesheet>
> >
> > Hopefully, I didn't include too much detail.
> >
> > Any help appreciated.  Thanks.

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.