Home. 
.

transparent

transparent

transparent

Altova Mailing List Archives


Re: [xsl] XSLT/XPath Question (Grouping Authors by First Character of Last Name)

From: "Dimitre Novatchev" <dnovatchev@--------->
To:
Date: 3/4/2007 3:25:00 AM
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.


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