I have an XML file that lists classes under a degree program. I have created a XSLT (with help) that successfully creates groups of classes under the degree name. But the client wants a third level that identifies elective and non-elective classes. The elective field is listed with the data “Y” if it is an elective and “N” if is not, or otherwise a “program requirement”.
I need to add another level to the XSLT that groups classes under a title “Program Requirement” if it has an “N” in the element <FlagElectives1>.
I think I need to create another key based on this element, right, and then create a template that creates a xsl:text title that says either: “Program Requirement” or “Program Elective” but I am stuck. I’ve never done three-level grouping before.
Here’s my XSLT:
<?xml version="1.0"?>
<!-- DWXMLSource="STX049 Catalog parsed.xml" -->
<!DOCTYPE xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/">
<CrystalReport>
<xsl:apply-templates/>
</CrystalReport>
</xsl:template>
<xsl:key name="degrees-by-title" match="CrystalReport/Group/Group/Group/Details" use="Section/ICCB1" />
<xsl:template match="CrystalReport/Group/Group/Group">
<Degree>
<xsl:for-each select="Details[count(. | key('degrees-by-title', Section/ICCB1)[1]) = 1]">
<xsl:sort select="Section/ACADPROGRAMSID1" />
<department>
<Degreetitle>
<xsl:apply-templates select="Section/ACPGDEGREE1" />
</Degreetitle>
<Certtitle>
<xsl:apply-templates select="Section/CCD11" />
</Certtitle>
<DegreeDesc>
<xsl:value-of select="Section/ACPGCOMMENTS1"/>
</DegreeDesc>
<ICCBcode>
<xsl:value-of select="Section/ICCB1"/>
</ICCBcode>
<ProgramID>
<xsl:value-of select="Section/ACADPROGRAMSID1"/>
</ProgramID>
<xsl:for-each select="key('degrees-by-title', Section/ICCB1)">
<xsl:sort select="Section/FlagElectives1" order="ascending" />
<xsl:sort select="Section/DEPARTMENT11" />
<xsl:sort select="Section/CRSNO1" />
<Details>
<class>
<deptname>
<xsl:value-of select="Section/DEPARTMENT11"/>
</deptname>
<courseno>
<xsl:value-of select="Section/CRSNO1"/>
</courseno>
<classname>
<xsl:value-of select="Section/CRSTITLE1"/>
</classname>
<classcredit>
<xsl:value-of select="Section/CRSMINCRED1"/>
</classcredit>
<Elective>
<xsl:value-of select="Section/FlagElectives1" />
</Elective>
</class>
</Details>
</xsl:for-each>
</department>
</xsl:for-each>
</Degree>
</xsl:template>
<xsl:template match="Section/ACPGDEGREE1[child::node()]">
<xsl:value-of select="."/>
<xsl:text> DEGREE</xsl:text>
</xsl:template>
<xsl:template match="Section/CCD11[child::node()]">
<xsl:text> CERTIFICATE</xsl:text>
</xsl:template>
</xsl:stylesheet>
Here is the structure of my XML:
<?xml version="1.0" encoding="UTF-8"?>
<CrystalReport>
<Group Level="1">
<Group Level="2">
<Group Level="3">
<Details>
<Section>
<ACPGDEGREE1>AAS</ACPGDEGREE1>
<CCD11/>
<ACPGCOMMENTS1>The Accounting program</ACPGCOMMENTS1>
<ICCB1>3203</ICCB1>
<ACADPROGRAMSID1>ACCOU.AAS</ACADPROGRAMSID1>
<CRSNO1>1110</CRSNO1>
<ACRBPRINTEDSPEC1/>
<ACPGHOMELANGNOTREQDRSN1>General Education</ACPGHOMELANGNOTREQDRSN1>
<CRSMINCRED1>2</CRSMINCRED1>
<ACPGAREAOFSTUDY1>Accounting</ACPGAREAOFSTUDY1>
<CRSTITLE1>Using Computers: An Introduction</CRSTITLE1>
<DEPARTMENT11>ACCOU</DEPARTMENT11>
<CRSSUBJECT1>CIS</CRSSUBJECT1>
<ACRBLABEL1>CIS REQUIREMENT</ACRBLABEL1>
<CRSMAXCRED1/>
<FlagElectives1>N</FlagElectives1>
</Section>
</Details>
<Details>
<Section>
<ACPGDEGREE1>AAS</ACPGDEGREE1>
<CCD11/>
<ACPGCOMMENTS1>The Accounting program</ACPGCOMMENTS1>
<ICCB1>3203</ICCB1>
<ACADPROGRAMSID1>ACCOU.AAS</ACADPROGRAMSID1>
<CRSNO1>1150</CRSNO1>
<ACRBPRINTEDSPEC1/>
<ACPGHOMELANGNOTREQDRSN1>General Education</ACPGHOMELANGNOTREQDRSN1>
<CRSMINCRED1>3</CRSMINCRED1>
<ACPGAREAOFSTUDY1>Accounting</ACPGAREAOFSTUDY1>
<CRSTITLE1>Intro to Computer</CRSTITLE1>
<DEPARTMENT11>ACCOU</DEPARTMENT11>
<CRSSUBJECT1>CIS</CRSSUBJECT1>
<ACRBLABEL1>CIS</ACRBLABEL1>
<CRSMAXCRED1/>
<FlagElectives1>Y</FlagElectives1>
</Section>
</Details>
</Group>
</Group>
</Group>
</CrystalReport>
The first level of grouping should be based on the element <DEPARTMENT11>. The title of the various degrees and certificates is found in the field <ACPGAREAOFSTUDY1>
The second level unique field in all this is <ACADPROGRAMSID1>
Here is the desired output:
<CrystalReport>
<Degrees>
<!--group and repeat "Degrees" for-each based on element ACPGAREAOFSTUDY1-->
<areaofstudy>Accounting</areaofstudy>
<Degree>
<department>
<!--group and repeat "department" for-each based on element ICCB1-->
<Degreetitle>AAS DEGREE</Degreetitle>
<Certtitle />
<DegreeDesc>The Accounting program</DegreeDesc>
<ICCBcode>3203</ICCBcode>
<ProgramID>ACCOU.AAS</ProgramID>
<!--group and repeat "Details" for-each based on element ACADPROGRAMSID1 under titles "Program Requirement" or "Program Elective" based on element "FlagElectives1"-->
<h1>Program Requirements</h1>
<Details>
<class>
<deptname>ACCOU</deptname>
<courseno>1150</courseno>
<classname>Intro to Computer</classname>
<classcredit>3</classcredit>
<Elective>N</Elective>
</class>
</Details>
<h1>Program Electives</h1>
<Details>
<class>
<deptname>ACCOU</deptname>
<courseno>1110</courseno>
<classname>Using Computers: An Introduction</classname>
<classcredit>2</classcredit>
<Elective>Y</Elective>
</class>
</Details>
</department>
</Degree>
<Degree>
<department>
<Degreetitle>AAS DEGREE</Degreetitle>
<Certtitle />
<DegreeDesc>The Accounting program</DegreeDesc>
<ICCBcode>3203</ICCBcode>
<ProgramID>ACCOU.AAS</ProgramID>
<h1>Program Requirements</h1>
<Details>
<class>
<deptname>ACCOU</deptname>
<courseno>1150</courseno>
<classname>Intro to Computer</classname>
<classcredit>3</classcredit>
<Elective>Y</Elective>
</class>
</Details>
<h1>Program Electives</h1>
<Details>
<class>
<deptname>ACCOU</deptname>
<courseno>1110</courseno>
<classname>Using Computers: An Introduction</classname>
<classcredit>2</classcredit>
<Elective>N</Elective>
</class>
</Details>
</department>
</Degree>
</Degrees>
</CrystalReport>
I did a bit of cleanup on your XSLT. Any time you have a
for-eachnested inside afor-each, that’s a good sign that your XSLT needs some refactoring. I think I’ve understood what you mean by grouping the courses by whether they are electives or not (though you haven’t indicated how you want to represent that), so what I came up with is the following:The elective grouping is achieved through the
call-templateitems, that select courses by whether or not they are electives:When run on your sample input, this XSLT produces:
Note the
h1elements noting the start of the requirement and elective groups. If you would like this represented some other way, please clarify that.