xsl-list
[Top] [All Lists]

Re: [xsl] Grouping simple flat structure

2008-03-17 06:01:36
On 17/03/2008, Ian Proudfoot <ian(_dot_)proudfoot(_at_)itp-x(_dot_)co(_dot_)uk> 
wrote:
I have a blind spot when it comes to grouping flat XML structure using XSLT
 1.0.

 My source XML structure is typically as follows (simplified for clarity):

 <section>
  <title/>
  <warning/>
  <warning/>
  <para/>
  <warning/>
  <warning/>
  <para/>
  <para/>
 </section>

 I would like to group adjacent <warning> elements to give this structure:

 <section>
  <title/>
  <w-group>
    <warning/>
    <warning/>
  </w-group>
  <para/>
  <w-group>
    <warning/>
    <warning/>
  </w-group>
  <para/>
  <para/>
 </section>

 I've tried using Muenchian Grouping, but I'm going wrong somewhere. I
 started by trying to identify the start of each group using <xsl:template
 match="warning[(preceding-sibling::*[1])[not(self::warning)]]">... As a
 starting point is this correct, it does seem to capture the first warning in
 each group? After that I cannot grab the following <warning> sibling
 elements correctly.

You can use the "sibling-recursion" template (also known as the
"modified identity tempate") which walks the sibling axis one node at
time:

   <xsl:template match="@* | node()">
      <xsl:copy>
         <xsl:apply-templates select="@*"/>
         <xsl:apply-templates select="node()[1]"/>
      </xsl:copy>
      <xsl:apply-templates select="following-sibling::node()[1]"/>
   </xsl:template>

Then have a specific template to process <warning> elements - output
the container element and then process the warning using a special
moded template to differentiate it from this template.  The next
non-warning element is processed after the container element.

  <xsl:template match="warning">
            <w-group>
                      <xsl:apply-templates select="." mode="copy"/>             
            </w-group>
            <xsl:apply-templates
select="(following-sibling::*[not(self::warning)])[1]"/>
  </xsl:template>

This is the template that effectively groups the warnings - it copies
the current warning (or probably processes it in your real transform)
and then processes the next node as long as it's a warning:

    <xsl:template match="warning" mode="copy">
            <xsl:copy-of select="."/>   
            <xsl:apply-templates
select="following-sibling::*[1][self::warning]" mode="copy"/>
    </xsl:template>


cheers
-- 
Andrew Welch
http://andrewjwelch.com
Kernow: http://kernowforsaxon.sf.net/

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>