[xsl] Grouping within a group

Subject: [xsl] Grouping within a group
From: "Rick Quatro" <rick@xxxxxxxxxxxxxx>
Date: Sat, 10 Aug 2013 21:53:57 -0400
Hi,

I have a (basically) flat XML file:

<?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>

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:

<?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>
      <Authors>Authors One</Authors>
      <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>
      <Authors>Author Two</Authors>
      <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>

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.

<?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[1]" />
        </data>
    </xsl:template>
    
    <xsl:template match="Category">
        <xsl:element name="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="following-sibling::*[1][not(self::Category)]"
mode="in-case-siblings"/>
        </xsl:element>
        <xsl:apply-templates select="following-sibling::Category[1]"/>
    </xsl:template>
    
    <xsl:template match="*" mode="in-case-siblings">
        <xsl:copy-of select="." />
        <xsl:apply-templates
            select="following-sibling::*[1][not(self::Category)]"
mode="in-case-siblings"/>
    </xsl:template>
    
    <xsl:template match="Category" mode="in-case-siblings"/>

    <xsl:template match="DifferentialDiagnosis" mode="in-case-siblings">
        
        <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:apply-templates
            select="following-sibling::*[1][not(self::Category)]"
mode="in-case-siblings"/>            
    </xsl:template>
        
</xsl:stylesheet>

Thanks in advance.

Rick

Current Thread