RE: [xsl] For-each-group groups elements before the first group-starting-with element

Subject: RE: [xsl] For-each-group groups elements before the first group-starting-with element
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 11 May 2010 09:05:56 +0100
group-starting-with allocates every selected item to one group; it starts a
new group for the first item and for every item that matches the pattern.

This means it is often necessary to treat the first group specially; in this
case the logic might be 

     <xsl:for-each-group select = "*" group-starting-with = "h1" >
         <xsl:apply-templates select="." mode="group"/>
     </xsl:for-each-group>

     <xsl:template match="h1" mode="group">
         <section>
            <xsl:apply-templates select="current-group()"/>
         </section>
     </xsl:template>

     <xsl:template match="*" mode="group">
        <xsl:apply-templates select="current-group()"/>
     </xsl:template>

Regards,

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

> -----Original Message-----
> From: Peter Desjardins [mailto:peter.desjardins.us@xxxxxxxxx] 
> Sent: 11 May 2010 03:50
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] For-each-group groups elements before the 
> first group-starting-with element
> 
> Hi. I'm new to XSLT and I'm trying to write a 2.0 stylesheet 
> to wrap HTML elements in DocBook <section> elements.  I'm 
> finding that <xsl:for-each-group> wraps elements in a 
> <section> even when they are not preceded by the element I 
> name in the group-starting-with attribute.
> 
> For example, I'm converting the HTML <body> element to a 
> DocBook <chapter> element. If the HTML includes <p> elements 
> before the first <h1> element, they should become <para> 
> elements that are children of the <chapter> element. I name 
> <h1> in the group-starting-with attribute but my output 
> includes a <section> element around the first <para> elements.
> 
> My processor is Saxon HE 9.2.1.1. I've pasted the source, 
> stylesheet, and output below. Am I using the for-each-group 
> element incorrectly? I figured out a way to work around this 
> problem by including a predicate [preceding-sibling::h1] in 
> the select attribute for it.  However, this won't work when I 
> need to wrap <h2> and <h3> sections later in the document.
> 
> Has anyone dealt with this situation before?  Thanks for your help.
> 
> Peter
> 
> ***********  Source  ***********
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <html>
>     <body>
>         <p>Acorn</p>
>         <p>Bee</p>
>         <h1>1 Heading One</h1>
>         <p>Caterpillar</p>
>         <p>Dragonfly</p>
>     </body>
> </html>
> 
> ***********  Stylesheet  ***********
> 
> <xsl:template match = "body" >
>     <xsl:for-each-group select = "*" group-starting-with = "h1" >
>         <xsl:element name="section">
>             <xsl:apply-templates select="current-group()"/>
>         </xsl:element>
>     </xsl:for-each-group>
> </xsl:template>
> 
> ***********  Output  ***********
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <book>
>    <chapter>
>       <section>
>          <para>Acorn</para>
>          <para>Bee</para>
>       </section>
>       <section>
>          <title>1 Heading One</title>
>          <para>Caterpillar</para>
>          <para>Dragonfly</para>
>       </section>
>    </chapter>
> </book>

Current Thread