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: Mukul Gandhi <gandhi.mukul@xxxxxxxxx>
Date: Tue, 11 May 2010 09:40:12 +0530
Here's a stylesheet which solves this problem:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                       version="2.0">

  <xsl:output method="xml" indent="yes" />

  <xsl:template match="html">
      <book>
	  <chapter>
	      <xsl:apply-templates select="body/h1[1]/preceding-sibling::p" />
	      <xsl:for-each-group select="body/*" group-starting-with="h1">
		 <xsl:if test="position() &gt; 1">
                    <section>
                       <xsl:apply-templates select="current-group()"/>
                    </section>
		  </xsl:if>
              </xsl:for-each-group>
	  </chapter>
      </book>
  </xsl:template>

  <xsl:template match="h1">
    <title>
	<xsl:apply-templates />
     </title>
  </xsl:template>

  <xsl:template match="p">
    <para>
	<xsl:copy-of select="node()" />
     </para>
  </xsl:template>

</xsl:stylesheet>

For the output you're seeking, you need to discard the 1st group. The
explanation of group formation, with 'group-starting-with' can be
found at:

http://www.w3.org/TR/xslt20/#xsl-for-each-group

On Tue, May 11, 2010 at 8:20 AM, Peter Desjardins
<peter.desjardins.us@xxxxxxxxx> wrote:
> Hi. I'm new to XSLT and I'm trying to write a 2.0 stylesheet to wrap
> HTML elements in DocBook <section> elements. B 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. B 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? B Thanks for your help.
>
> Peter
>
> *********** B Source B ***********
>
> <?xml version="1.0" encoding="UTF-8"?>
> <html>
> B  B <body>
> B  B  B  B <p>Acorn</p>
> B  B  B  B <p>Bee</p>
> B  B  B  B <h1>1 Heading One</h1>
> B  B  B  B <p>Caterpillar</p>
> B  B  B  B <p>Dragonfly</p>
> B  B </body>
> </html>
>
> *********** B Stylesheet B ***********
>
> <xsl:template match = "body" >
> B  B <xsl:for-each-group select = "*" group-starting-with = "h1" >
> B  B  B  B <xsl:element name="section">
> B  B  B  B  B  B <xsl:apply-templates select="current-group()"/>
> B  B  B  B </xsl:element>
> B  B </xsl:for-each-group>
> </xsl:template>
>
> *********** B Output B ***********
>
> <?xml version="1.0" encoding="UTF-8"?>
> <book>
> B  <chapter>
> B  B  B <section>
> B  B  B  B  <para>Acorn</para>
> B  B  B  B  <para>Bee</para>
> B  B  B </section>
> B  B  B <section>
> B  B  B  B  <title>1 Heading One</title>
> B  B  B  B  <para>Caterpillar</para>
> B  B  B  B  <para>Dragonfly</para>
> B  B  B </section>
> B  </chapter>
> </book>



--
Regards,
Mukul Gandhi

Current Thread