RE: [xsl] xslt 2.0: grouping flat element structures to make lists

Subject: RE: [xsl] xslt 2.0: grouping flat element structures to make lists
From: "Derek Revill" <derek@xxxxxxxxxxxxxxxxxx>
Date: Wed, 25 May 2005 22:23:46 +0100
Thanks Jay. Your example gets me some way by picking the right items for the
lists (I had something like that for one of my attempts) but there are still
a couple of serious problems in my scenario that mean I can't use it:

1. The parent element of the flat structure sequence can occur in a large
number of elements e.g. section, subsection1, subsection2, p, list etc.
Since I don't know the parent (can't really code for all of them) I don't
have a nice parent node template in which to place my xsl:for-each-group
code. 

2. In your example the intermingling nodes are lost on output. I need to
preserve all of these on output, and keep them in the same relative
positions.

For these two reasons I felt forced to attach my list nesting code on the
first <par class="Listbegin"> as the trigger to start the list, then try to
get the following node sequence (i.e. all list-items up to the next
non-list-item node) and close off the list.

Am I approaching this from the right angle?

A more challenging example xml might be.

<?xml version="1.0" encoding="UTF-8"?>
<Any-element>
 <a>some text</a>
 <par class="Listbegin">Fruit</par>
 <par class="Listitem>Apple</par>
 <par class="Listitem>Orange</par>
 <par class="Listitem>Pear</par>
 <a>more text</a>
 <par class="Listbegin">Colours</par>
 <par class="Listitem>Red</par>
 <par class="Listitem>Green</par>
 <par class="Listitem>Blue</par>
 <par class="Listbegin">Shapes</par>
 <par class="Listitem>Triangle</par>
 <par class="Listitem>Circle</par>
 <par class="Listitem>Square</par>
 <a>yet more text</a>
</Any-element>

to produce

<?xml version="1.0" encoding="UTF-8"?>
<data>
 <a>some text</a>
 <list>
  <head>Fruit</head>
  <item>Apple</item>
  <item>Orange</item>
  <item>Pear</item>
 </list>
 <a>more text</a>
 <list>
  <head>Colours</head>
  <item>Red</item>
  <item>Green</item>
  <item>Blue</item>
 </list>
<list>
  <head>Shapes</head>
  <item>Triangle</item>
  <item>Circle</item>
  <item>Square</item>
 </list>
 <a>yet more text</a>
</data>	 

Any more pearls of wisdom on the appreciated!

Derek

> -----Original Message-----
> From: JBryant@xxxxxxxxx [mailto:JBryant@xxxxxxxxx]
> Sent: 25 May 2005 20:30
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: Re: [xsl] xslt 2.0: grouping flat element structures to make
> lists
> 
> Hi, Derek,
> 
> The trick is picking just the bits you want in the list. I took your
> sample lists and made a sample XML file and a stylesheet to demonstrate
> one way to do it (with apply-templates).
> 
> Here's the XML file (with non-list elements intermingled with the lists):
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <lists>
>   <par class="Listbegin">Fruit</par>
>   <par class="Listitem">Apple</par>
>   <par class="Listitem">Orange</par>
>   <par class="Listitem">Pear</par>
>   <something>thing1</something>
>   <something>thing2</something>
>   <par class="Listbegin">Colours</par>
>   <par class="Listitem">Red</par>
>   <par class="Listitem">Green</par>
>   <par class="Listitem">Blue</par>
> </lists>
> 
> And here's the XSL:
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="2.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> 
>   <xsl:template match="lists">
>     <lists>
>       <xsl:for-each-group select="*"
> group-starting-with="par[@class='Listbegin']">
>         <list>
>           <xsl:apply-templates
> select="current-group()/self::par[@class='Listbegin']|current-
> group()/self::par[@class='Listitem']"/>
>         </list>
>       </xsl:for-each-group>
>     </lists>
>   </xsl:template>
> 
>   <xsl:template match="par[@class='Listbegin']">
>     <head><xsl:value-of select="."/></head>
>   </xsl:template>
> 
>   <xsl:template match="par[@class='Listitem']">
>     <item><xsl:value-of select="."/></item>
>   </xsl:template>
> 
> </xsl:stylesheet>
> 
> And here's the resulting output:
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <lists>
>   <list>
>     <head>Fruit</head>
>     <item>Apple</item>
>     <item>Orange</item>
>     <item>Pear</item>
>   </list>
>   <list>
>     <head>Colours</head>
>     <item>Red</item>
>     <item>Green</item>
>     <item>Blue</item>
>   </list>
> </lists>
> 
> Does that come near the mark or did I misunderstand?
> 
> (And this time I remembered to use the self axis. Thanks again to David
> Carlisle.)
> 
> Jay Bryant
> Bryant Communication Services
> (presently consulting at Synergistic Solution Technologies)
> 
> 
> 
> 
> 
> "Derek Revill" <derek@xxxxxxxxxxxxxxxxxx>
> 05/25/2005 01:07 PM
> Please respond to
> xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> 
> 
> To
> <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
> cc
> 
> Subject
> [xsl] xslt 2.0: grouping flat element structures to make lists
> 
> 
> 
> 
> 
> 
> Hello
> 
> Using XSLT 2.0 (running Saxon 8.4) I am grappling with a pretty standard
> grouping issue, attempting to utilize some of XSLT v2 grouping
> possibilities
> but with no success (reading the W3C spec and a scan of the archive
> haven't
> proved helpful, MK book is on order!).
> 
> Mid flow I have:
> 
> ..
> ..
> <par class="Listbegin">Fruit</par>
> <par class="Listitem>Apple</par>
> <par class="Listitem>Orange</par>
> <par class="Listitem>Pear</par>
> <par class="Listbegin">Colours</par>
> <par class="Listitem>Red</par>
> <par class="Listitem>Green</par>
> <par class="Listitem>Blue</par>
> ..
> ..
> 
> I just need to output
> 
> ..
> ..
> <list>
>                  <head>Fruit</head>
>                  <item>Apple</item>
>                  <item>Orange</item>
>                  <item>Pear</item>
> </list>
> <list>
>                  <head>Colours</head>
>                  <item>Red</item>
>                  <item>Green</item>
>                  <item>Blue</item>
> </list>
> 
> Note: I'm midway through processing any section when I encounter the <par
> class="Listbegin">. The signal that a list has ended can be any
> following-sibling that isn't <par class="Listitem>..</par> or the end of
> the
> parent element I'm in. Of course, lists don't always come in pairs like
> above.
> 
> Should I try to match on the <par class="Listbegin"> then scoop-up all
> relevant following nodes, which was my strategy up to now? Haven't been
> able
> to find a way to scoop-up only the following nodes that are relevant.
> 
> Any advice gratefully received. Numerous attempts using for-each-group and
> various group-by strategies have been fruitless, probably I just haven't
> quite grasped it!
> 
> Thanks
> 
> Derek Revill

Current Thread