I'm working on an XSL Stylsheet where Students are grouped in this order:
college->level->department->chair->concentration->student
So basically the structure would be "groups within groups". Let me know if the following makes sense. Let me know if you need clarification!
This is the original XML that I'm trying to transform:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataroot>
<student>
<name_sort>Doe, John</name_sort>
<name>John Doe</name>
<level>Undergrad</level>
<concentration>Studio Art</concentration>
<college>College 1</college>
<department>Department 1</department>
<chair>Chair Name</chair>
</student>
<student>
<name_sort>James, Lisa</name_sort>
<name>Lisa James</name>
<level>Undergrad</level>
<concentration>Studio Art</concentration>
<college>College 1</college>
<department>Department 1</department>
<chair>Chair Name</chair>
</student>
<dataroot>
XML Output with applied XSL stylesheet:
<Root>
<!-- Group by College -->
<college>College 1</college>
<!-- Group by Level -->
<level>Undergraduate</level>
<!-- Group by Department -->
<department>Department 1</department>
<!-- Group by Chair -->
<chair>Chair Name</chair>
<!-- Group by Concentration -->
<concentration>Studio Art</concentration>
<!-- List Students with matching concentration under parent groups -->
<student>
<name>John Doe</name>
</student>
<student>
<name>Lisa James</name>
</student>
<!-- Repeat loop -->
</Root>
This is my attempt, but students don't group correctly. Some students that are "undegraduate" show up under "graduate" and some concentration groups are duplicated...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Keys for grouping -->
<xsl:key name="colleges" match="student" use="college"/>
<xsl:key name="levels" match="student" use="level"/>
<xsl:key name="departments" match="student" use="department"/>
<xsl:key name="chairs" match="student" use="chair"/>
<xsl:key name="concentrations" match="student" use="concentration"/>
<xsl:template match="/dataroot">
<Root>
<xsl:for-each select="student[generate-id() = generate-id(key('colleges', college)[1])]">
<xsl:sort select="college" order="ascending"/>
<xsl:for-each select="key('colleges', college)[generate-id() = generate-id(key('levels', level)[1])]">
<xsl:sort select="level" order="ascending"/>
<college><xsl:value-of select="college"/></college>
<xsl:text>
</xsl:text>
<level><xsl:value-of select="level"/> degree recipients</level>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('levels', level)[generate-id() = generate-id(key('departments', department)[1])]">
<xsl:sort select="department" order="ascending"/>
<department><xsl:value-of select="department"/></department>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('departments', department)[generate-id() = generate-id(key('chairs', chair)[1])]">
<xsl:sort select="chair" order="ascending"/>
<chair><xsl:value-of select="chair"/></chair>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('chairs', chair)[generate-id() = generate-id(key('concentrations', concentration)[1])]">
<xsl:sort select="concentration" order="ascending"/>
<concentration><xsl:value-of select="concentration"/></concentration>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('concentrations', concentration)">
<xsl:sort select="name_sort" order="ascending"/>
<student>
<name><xsl:value-of select="name"/></name>
<xsl:text>
</xsl:text>
</student>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</Root>
</xsl:template>
Can anyone help me?
It is easy with XSLT 2 or 3 to nest xsl:for-each-group
the way you try it with xsl:for-each
but with XSLT 1 and Muenchian grouping you will need to have the second level key include the first level key with e.g.
<xsl:key name="colleges" match="student" use="college"/>
<xsl:key name="levels" match="student" use="concat(college, '|', level)"/>
and use e.g.
<xsl:for-each select="key('colleges', college)[generate-id() = generate-id(key('levels', concat(college, '|', level))[1])]">
and then you need to use the same approach with the third level key
<xsl:key name="departments" match="student" use="concat(department, '|', college, '|', level)"/>
and
<xsl:for-each select="key('levels', concat(college, '|', level))[generate-id() = generate-id(key('departments', concat(department, '|', college, '|', level))[1])]">
and so on.