RE: [xsl] Grouping within a group

Subject: RE: [xsl] Grouping within a group
From: "Rick Quatro" <rick@xxxxxxxxxxxxxx>
Date: Sun, 11 Aug 2013 08:58:33 -0400
Hi Ken,

Thank you for your generous help. I am not attached to my original code; I
want to learn how to do this the right way, so seeing how you approach it
will be very helpful. Thanks again.

Rick

-----Original Message-----
From: G. Ken Holman [mailto:g.ken.holman@xxxxxxxxx] On Behalf Of G. Ken
Holman
Sent: Saturday, August 10, 2013 10:23 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx; xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Grouping within a group

At 2013-08-10 21:53 -0400, Rick Quatro wrote:
>I have a (basically) flat XML file:
>...
>With some help from the group, I got a single level of nesting, 
>starting with each new category. However, I just found out that I need 
>some sub-grouping. My finished XML needs to look like this:
>...
>Here is my stylesheet. It gives me what I need, except for the nested 
><TeachingPoint> and <SuggestedReading> elements. I am not sure exactly 
>how to approach this with XSLT 1.0.

I have a complete solution below, but I refactored your extensive use of
modes and of recursive apply-templates of siblings as I found them very
confusing and really unnecessary.  In my code below you'll see I use no
modes or pushing siblings, and I act on the data in a top-down fashion
rather than a sideways fashion.

I hope you find this helpful.  Perhaps you can just extract what I did for
teaching points and suggested readings if you really want to keep the
original code, but I suggest you compare the maintainability of the two
solutions.

. . . . . . . . Ken

t:\ftemp>type rick.xml
<?xml version="1.0" encoding="UTF-8"?>
<Cases>
     <Story>
         <Category>Category: Subcategory</Category>
         <CaseTitle>Title One</CaseTitle>
         <Institution>Institution One</Institution >
         <Author>Authors One</Author>
         <History>History One</History>
         <DifferentialDiagnosis>Sick</DifferentialDiagnosis>
         <DifferentialDiagnosis>Sicker</DifferentialDiagnosis>
         <DifferentialDiagnosis>Sickest</DifferentialDiagnosis>
         <TeachingPoint>Point1</TeachingPoint>
         <TeachingPoint>Point2</TeachingPoint>
         <SuggestedReading>Reading1</SuggestedReading>
         <SuggestedReading>Reading2</SuggestedReading>
         <Category>Category One: Subcategory</Category>
         <CaseTitle>Title Two</CaseTitle>
         <Institution>Title Two</Institution >
         <Author>Author Two</Author>
         <History>History Two</History>
         <DifferentialDiagnosis>Sickly</DifferentialDiagnosis>
         <DifferentialDiagnosis>Sicklier</DifferentialDiagnosis>
         <DifferentialDiagnosis>Sickliest</DifferentialDiagnosis>
         <TeachingPoint>Point1</TeachingPoint>
         <TeachingPoint>Point2</TeachingPoint>
         <SuggestedReading>Reading1</SuggestedReading>
         <SuggestedReading>Reading2</SuggestedReading></Story>
</Cases>
t:\ftemp>call xslt rick.xml rick.xsl
<?xml version="1.0" encoding="utf-8"?>

<data>
    <newRecord>
       <Category>Category</Category>
       <Subcategory>Subcategory</Subcategory>
       <Case>1</Case>
       <CaseTitle>Title One</CaseTitle>
       <Institution>Institution One</Institution>
       <Author>Authors One</Author>
       <History>History One</History>
       <DifferentialDiagnosis1>Sick</DifferentialDiagnosis1>
       <DifferentialDiagnosis2>Sicker</DifferentialDiagnosis2>
       <DifferentialDiagnosis3>Sickest</DifferentialDiagnosis3>
       <TeachingPoints>
          <TeachingPoint>Point1</TeachingPoint>
          <TeachingPoint>Point2</TeachingPoint>
       </TeachingPoints>
       <SuggestedReadings>
          <SuggestedReading>Reading1</SuggestedReading>
          <SuggestedReading>Reading2</SuggestedReading>
       </SuggestedReadings>
    </newRecord>
    <newRecord>
       <Category>Category One</Category>
       <Subcategory>Subcategory</Subcategory>
       <Case>2</Case>
       <CaseTitle>Title Two</CaseTitle>
       <Institution>Title Two</Institution>
       <Author>Author Two</Author>
       <History>History Two</History>
       <DifferentialDiagnosis1>Sickly</DifferentialDiagnosis1>
       <DifferentialDiagnosis2>Sicklier</DifferentialDiagnosis2>
       <DifferentialDiagnosis3>Sickliest</DifferentialDiagnosis3>
       <TeachingPoints>
          <TeachingPoint>Point1</TeachingPoint>
          <TeachingPoint>Point2</TeachingPoint>
       </TeachingPoints>
       <SuggestedReadings>
          <SuggestedReading>Reading1</SuggestedReading>
          <SuggestedReading>Reading2</SuggestedReading>
       </SuggestedReadings>
    </newRecord>
</data>

t:\ftemp>type rick.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

     <xsl:output indent="yes" />

     <xsl:template match="Cases/Story">
         <data>
             <xsl:apply-templates select="Category" />
         </data>
     </xsl:template>

     <xsl:key name="category" match="Story/*[not(self::Category)]"
              use="generate-id(preceding-sibling::Category[1])"/>

      <xsl:template match="Category">
         <newRecord>
             <Category><xsl:value-of select="substring-before(.,':
')"/></Category>
             <Subcategory><xsl:value-of select="substring-after(.,':
')"/></Subcategory>
             <Case><xsl:number count="Category"/></Case>
             <xsl:apply-templates select="key('category',generate-id(.))"/>
         </newRecord>
     </xsl:template>

     <xsl:template match="Story/*" priority="-1">
         <xsl:copy-of select="." />
     </xsl:template>

     <xsl:template match="DifferentialDiagnosis">

         <xsl:variable name="diagnosis">
             <xsl:value-of select="1 +
count(preceding-sibling::DifferentialDiagnosis) -
count(preceding-sibling::Category[1]/preceding-sibling::DifferentialDiagnosi
s)"/>
         </xsl:variable>
         <xsl:element name="{concat(name(),$diagnosis)}"><xsl:value-of
select="."/></xsl:element>
     </xsl:template>

<xsl:key name="teaching" match="TeachingPoint"
          use="generate-id(preceding-sibling::Category[1])"/>

<xsl:template match="TeachingPoint">
   <xsl:if test="not(preceding-sibling::*[1][self::TeachingPoint])">
     <!--now at the first of a set of teaching points-->
     <TeachingPoints>
       <xsl:copy-of select="key('teaching',
 
generate-id(preceding-sibling::Category[1]))"/>
     </TeachingPoints>
   </xsl:if>
</xsl:template>

<xsl:key name="suggested" match="SuggestedReading"
          use="generate-id(preceding-sibling::Category[1])"/>

<xsl:template match="SuggestedReading">
   <xsl:if test="not(preceding-sibling::*[1][self::SuggestedReading])">
     <!--now at the first of a set of suggested readings-->
     <SuggestedReadings>
       <xsl:copy-of select="key('suggested',
 
generate-id(preceding-sibling::Category[1]))"/>
     </SuggestedReadings>
   </xsl:if>
</xsl:template>

</xsl:stylesheet>

t:\ftemp>rem Done!


--
Public XSLT, XSL-FO, and UBL classes in the Netherlands     Oct 2013 |
Public XSLT, XSL-FO, UBL and code list classes in Australia Oct 2013 |
Contact us for world-wide XML consulting and instructor-led training | Free
5-hour lecture: http://www.CraneSoftwrights.com/links/udemy.htm |
Crane Softwrights Ltd.            http://www.CraneSoftwrights.com/s/ |
G. Ken Holman                   mailto:gkholman@xxxxxxxxxxxxxxxxxxxx |
Google+ profile: https://plus.google.com/116832879756988317389/about |
Legal business disclaimers:    http://www.CraneSoftwrights.com/legal |

Current Thread