[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Tricky XSLT 2.0 grouping problem

Subject: Re: Tricky XSLT 2.0 grouping problem
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Fri, 10 Oct 2008 11:28:19 -0400
Re:  Tricky XSLT 2.0 grouping problem
At 2008-10-10 09:03 -0500, James Sulak wrote:
I have a tricky grouping problem that I'm running into a wall with.  I
thought it might be a fun challenge to throw out there.  I'm attempting
to group a flat list of <section> elements into a hierarchy based on
matching its number against different regular expressions.

Then you have to do one level at a time because of the ambiguity. You have to group each subgroup rather than trying to find all subgroups.


The list is assumed to be in the correct order. I have it working (the code is
below) with one exception: roman numerals.

You have to work recursively, determining only those that are in sequence. I used a predicate and codepoints assuming that the three levels that are grouped have members that are monotonically increasing.


How I try to help my students understand <xsl:for-each-group> is to read the name of the instruction as if it were "for the first member of each group", reminding them that in the loop the current node is at the first member of the group that was created. This helps them (and me!) remember what I can do wherever I am in my grouping code and helped me below.

I hope this helps you as well.

. . . . . . . . . Ken

t:\ftemp>type sulak.xml
<body>
<section><pnum>(a)</pnum><p>First-level section</p></section>
<section><pnum>(1)</pnum><p>Second-level section</p></section>
<section><pnum>(A)</pnum><p>Third-level section</p></section>
<section><pnum>(i)</pnum><p>Fourth-level section</p></section>
<section><pnum>(ii)</pnum><p>Fourth-level section</p></section>
<section><pnum>(B)</pnum><p>Third-level section</p></section>
<section><pnum>(2)</pnum><p>Second-level section</p></section>
<section><pnum>(A)</pnum><p>Third-level section</p></section>
</body>

t:\ftemp>call xslt2 sulak.xml sulak.xsl sulak.out
<?xml version="1.0" encoding="UTF-8"?>
<section>
   <pnum>(a)</pnum>
   <p>First-level section</p>
   <section>
      <pnum>(1)</pnum>
      <p>Second-level section</p>
      <section>
         <pnum>(A)</pnum>
         <p>Third-level section</p>
         <section>
            <pnum>(i)</pnum>
            <p>Fourth-level section</p>
         </section>
         <section>
            <pnum>(ii)</pnum>
            <p>Fourth-level section</p>
         </section>
      </section>
      <section>
         <pnum>(B)</pnum>
         <p>Third-level section</p>
      </section>
   </section>
   <section>
      <pnum>(2)</pnum>
      <p>Second-level section</p>
      <section>
         <pnum>(A)</pnum>
         <p>Third-level section</p>
      </section>
   </section>
</section><?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">

<xsl:output indent="yes"/>

<xsl:variable name="levels" select="('\([a-z]\)','\([1-9]\)','\([A-Z]\)')"/>

<xsl:template match="body">
  <xsl:call-template name="do-next-group">
    <xsl:with-param name="level" select="1"/>
    <xsl:with-param name="population" select="section"/>
  </xsl:call-template>
</xsl:template>

<xsl:template name="do-next-group">
  <xsl:param name="level"/>
  <xsl:param name="population"/>

<!--find all the first elements in the population at the current level-->
<!--the first is each one that is in sequence with the one immediately
before that matches the same level-->
<xsl:for-each-group select="$population"
group-starting-with="*[pnum[matches(.,$levels[$level])]]
[not( preceding-sibling::*[pnum[matches(.,$levels[$level])]] )
or string-to-codepoints(substring(pnum,2,1)) =
string-to-codepoints(substring(preceding-sibling::*
[pnum[matches(.,$levels[$level])]][1],2,1))
+1]">
<!--determine what to do based on how deep-->
<xsl:choose>
<xsl:when test="$level = count($levels)">
<!--at the last level, so everything after first is in the next level-->
<section>
<xsl:copy-of select="pnum,p"/>
<xsl:copy-of select="current-group()[position()>1]"/>
</section>
</xsl:when>
<xsl:otherwise>
<!--at other level, so need more grouping-->
<section>
<xsl:copy-of select="pnum,p"/>
<xsl:call-template name="do-next-group">
<xsl:with-param name="level" select="$level+1"/>
<xsl:with-param name="population"
select="current-group()[position()>1]"/>
</xsl:call-template>
</section>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>


</xsl:stylesheet>


-- Upcoming XSLT/XSL-FO hands-on courses: Wellington, NZ 2009-01 Training tools: Comprehensive interactive XSLT/XPath 1.0/2.0 video Video sample lesson: http://www.youtube.com/watch?v=PrNjJCh7Ppg Video course overview: http://www.youtube.com/watch?v=VTiodiij6gE G. Ken Holman mailto:gkholman@xxxxxxxxxxxxxxxxxxxx Crane Softwrights Ltd. http://www.CraneSoftwrights.com/s/ Male Cancer Awareness Nov'07 http://www.CraneSoftwrights.com/s/bc Legal business disclaimers: http://www.CraneSoftwrights.com/legal

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.