[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] A grouping question ?


Subject: Re: [xsl] A grouping question ?
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 31 Oct 2003 13:25:45 +0000

Hi Emilio,

> I have a XML file such as:
>
> <Content>
>     <Paragraph bullet='false'>
>         <Text txt='Hello World'/>
>     </Paragraph>
>     <Paragraph bullet='true'>
>         <Text txt='First Bulleted Hello World'/>
>     </Paragraph>
>     <Paragraph bullet='true'>
>         <Text txt='Second Bulleted Hello World'/>
>     </Paragraph>
>     <Paragraph bullet='false'>
>         <Text txt='A normal line of text'/>
>     </Paragraph>
>     <Paragraph bullet='true'>
>         <Text txt='Another bulleted line'/>
>     </Paragraph>
>     <Paragraph bullet='true'>
>         <Text txt='A second bulleted line'/>
>     </Paragraph>
> </Content>   
>
> And I want an HTML output like the following:
>
> <html>
>     <p>Hello World</p>
>     <ul>
>         <li>First Bulleted Hello World</li>
>         <li>Second Bulleted Hello World</li>
>     </ul>
>     <p>A normal line of text</p>
>     <ul>
>         <li>Another bulleted line</li>
>         <li>A second bulleted line</li>
>     </ul>
> </html>

This *is* a grouping problem, though you're right that it's not a
"normal" one. In fact, it's very similar to Dave Holden's "flattening"
problem, and I'd approach it the same way, by stepping through the
<Paragraph> elements one by one:

<xsl:template match="Content">
  <html>
    <!-- only apply templates to first Paragraph -->
    <xsl:apply-templates select="Paragraph[1]" />
  </html>
</xsl:template>

<xsl:template match="Paragraph[@bullet = 'false']">
  <!-- create p element -->
  <p>
    <xsl:apply-templates />
  </p>
  <!-- step on to next Paragraph element -->
  <xsl:apply-templates select="following-sibling::Paragraph[1]" />
</xsl:template>

<xsl:template match="Paragraph[@bullet = 'true']">
  <!-- create ul element -->
  <ul>
    <!-- populate by applying templates in item mode -->
    <xsl:apply-templates select="." mode="item" />
  </ul>
  <!-- step on to next non-bulleted Paragraph -->
  <xsl:apply-templates
    select="following-sibling::Paragraph[@bullet = 'false'][1]" />
</xsl:template>

<xsl:template match="Paragraph[@bullet = 'true']" mode="item">
  <!-- create list item -->
  <li>
    <xsl:apply-templates />
  </li>
  <!-- step on to next Paragraph -->
  <xsl:apply-templates select="following-sibling::Paragraph[1]"
                       mode="item" />
</xsl:template>

<!-- do nothing -->
<xsl:template match="Paragraph[@bullet = 'false']" mode="item" />

<xsl:template match="Text">
  <xsl:value-of select="@txt" />
</xsl:template>

It's a lot easier in XSLT 2.0:

<xsl:template match="Content">
  <html>
    <xsl:for-each-group select="Paragraph"
                        group-adjacent="@bullet">
      <xsl:choose>
        <xsl:when test="@bullet = 'false'">
          <xsl:apply-templates select="current-group()" />
        </xsl:when>
        <xsl:otherwise>
          <ul>
            <xsl:apply-templates select="current-group()" />
          </ul>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </html>
</xsl:template>

<xsl:template match="Paragraph[@bullet = 'false']">
  <p><xsl:apply-templates /></p>
</xsl:template>

<xsl:template match="Paragraph[@bullet = 'true']">
  <li><xsl:apply-templates /></li>
</xsl:template>

<xsl:template match="Text">
  <xsl:value-of select="@txt" />
</xsl:template>

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread
Keywords