Search code examples
xslt-2.0xslt-grouping

Group and Count data


I am working on trying to compute counts for each student assessment based on different steps in the review of test. Student test evaluation has multiple levels Application Evaluation, Written Test, Group Interview, Interview. I have find counts based on gender at each level.

xml:

<xd:StudentData xmlns:xd="urn:com.student.report/student_test">
<xd:StudentRecord>
<xd:StudentRequisition xd:Descriptor="1858 Economics"></xd:StudentRequisition>
<xd:StudentStatus xd:Descriptor="Pass"></xd:StudentStatus>
<xd:StudentApplication xd:Descriptor="1858 Economics"></xd:StudentApplication>
<xd:StudentID>S-1</xd:StudentID>
<xd:Gender xd:Descriptor="Male"></xd:Gender>
<xd:StudentDate>2020-01-01-12:00</xd:StudentDate>
<xd:Total_Score>75</xd:Total_Score>
<xd:ProfileStudentTestGroup>
<xd:StudentTest xd:Descriptor="Student Evaluation"></xd:StudentTest>
<xd:StudentTest_Status xd:Descriptor="Pass"></xd:StudentTest_Status>
<xd:StudentTest_Date>2020-01-31-12:00</xd:StudentTest_Date>
<xd:StudentTest_Result_Score>75</xd:StudentTest_Result_Score>
</xd:ProfileStudentTestGroup>
</xd:StudentRecord>
<xd:StudentRecord>
<xd:StudentRequisition xd:Descriptor="1500 Social Service"></xd:StudentRequisition>
<xd:StudentStatus xd:Descriptor="Fail"></xd:StudentStatus>
<xd:StudentApplication xd:Descriptor="1500 Social Service"></xd:StudentApplication>
<xd:StudentID>S-3</xd:StudentID>
<xd:Gender xd:Descriptor="Female"></xd:Gender>
<xd:StudentDate>2020-01-01-12:00</xd:StudentDate>
<xd:Total_Score>65</xd:Total_Score>
<xd:ProfileStudentTestGroup>
<xd:StudentTest xd:Descriptor="Student Evaluation"></xd:StudentTest>
<xd:StudentTest_Status xd:Descriptor="Pass"></xd:StudentTest_Status>
<xd:StudentTest_Date>2020-01-31-12:00</xd:StudentTest_Date>
<xd:StudentTest_Result_Score>65</xd:StudentTest_Result_Score>
</xd:ProfileStudentTestGroup>
</xd:StudentRecord>
<xd:StudentRecord>
<xd:StudentRequisition xd:Descriptor="1500 Social Service"></xd:StudentRequisition>
<xd:StudentStatus xd:Descriptor="Fail"></xd:StudentStatus>
<xd:StudentApplication xd:Descriptor="1500 Social Service"></xd:StudentApplication>
<xd:StudentID>S-4</xd:StudentID>
<xd:Gender xd:Descriptor="Female"></xd:Gender>
<xd:StudentDate>2020-01-01-12:00</xd:StudentDate>
<xd:Total_Score>67</xd:Total_Score>
<xd:ProfileStudentTestGroup>
<xd:StudentTest xd:Descriptor="Student Evaluation"></xd:StudentTest>
<xd:StudentTest_Status xd:Descriptor="Pass"></xd:StudentTest_Status>
<xd:StudentTest_Date>2020-01-31-12:00</xd:StudentTest_Date>
<xd:StudentTest_Result_Score>67</xd:StudentTest_Result_Score>
</xd:ProfileStudentTestGroup>
</xd:StudentRecord>
<xd:StudentRecord>
<xd:StudentRequisition xd:Descriptor="1858 Economics"></xd:StudentRequisition>
<xd:StudentStatus xd:Descriptor="Pass"></xd:StudentStatus>
<xd:StudentApplication xd:Descriptor="1858 Economics"></xd:StudentApplication>
<xd:StudentID>S-7</xd:StudentID>
<xd:Gender xd:Descriptor="Male"></xd:Gender>
<xd:StudentDate>2020-01-01-12:00</xd:StudentDate>
<xd:Total_Score>85</xd:Total_Score>
<xd:ProfileStudentTestGroup>
<xd:StudentTest xd:Descriptor="Student Evaluation"></xd:StudentTest>
<xd:StudentTest_Status xd:Descriptor="Pass"></xd:StudentTest_Status>
<xd:StudentTest_Date>2020-01-31-12:00</xd:StudentTest_Date>
<xd:StudentTest_Result_Score>85</xd:StudentTest_Result_Score>
</xd:ProfileStudentTestGroup>
</xd:StudentRecord>
</xd:StudentData>

xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="xsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xd="urn:com.student.report/student_test">

<xsl:iterate select="StudentData/StudentRecord">

    <xsl:param name="male_pass_count" select="0.00" as="xs:integer"/>
    <xsl:param name="male_fail_count" select="0.00" as="xs:integer"/>
    <xsl:param name="female_pass_count" select="0.00" as="xs:integer"/>
    <xsl:param name="female_fail_count" select="0.00" as="xs:integer"/>
    <xsl:param name="StudentTest" select="{/xd:StudentTest/@xd:Descriptor}" as="xs:string"/>

    <xsl:choose>

    <xsl:when test="{/xd:Gender/@xd:Descriptor} = 'Male'">

        <xsl:if test="{/xd:StudentTest_status/@xd:Descriptor} = 'Pass'">
        <xsl:with-param name="male_pass_count" select="$male_pass_count + 1"/>
        </xsl:if>

        <xsl:if test="{/xd:StudentTest_status/@xd:Descriptor} = 'Fail'">
        <xsl:with-param name="male_fail_count" select="$male_fail_count + 1"/>
        </xsl:if>

    </xsl:when> 

    <xsl:when test="{/xd:Gender/@xd:Descriptor} = 'Female'">

        <xsl:if test="{/xd:StudentTest_status/@xd:Descriptor} = 'Pass'">
        <xsl:with-param name="female_pass_count" select="$female_pass_count + 1"/>
        </xsl:if>

        <xsl:if test="{/xd:StudentTest_status/@xd:Descriptor} = 'Fail'">
        <xsl:with-param name="female_fail_count" select="$female_fail_count + 1"/>
        </xsl:if>

    </xsl:when> 

    </xsl:choose>

<xsl:on-completion>

    <student id="{$StudentTest}">
        <male_pass_count>{$male_pass_count}</male_pass_count>
        <male_fail_count>{$male_fail_count}</male_fail_count>
        <female_pass_count>{$female_pass_count}</female_pass_count>
        <female_fail_count>{$female_fail_count}</female_fail_count>

    </student>

</xsl:on-completion>

</xsl:iterate>

output:

StudentRequisition  StudentTest             MalePass    MaleFail    FemalePass  FemaleFail
1858 Economics      Application evaluation  22          0           10          0
1858 Economics      Interview               6           11          0           5
1858 Economics      Written Test            2           0           2           0
1500 Social Service Application evaluation  10          12          10          12
1500 Social Service Interview               0           0           0           0
1500 Social Service Written Test            0           0           0           0

Solution

  • If you use an XSLT 3 processor (as your use it xsl:iterate indicates) you can use for-each-group with a composite grouping key on the requisition and the test I think:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xpath-default-namespace="urn:com.student.report/student_test"
        xmlns:xd="urn:com.student.report/student_test"
        expand-text="yes"
        exclude-result-prefixes="#all"
        version="3.0">
    
      <xsl:output indent="yes" method="html" html-version="5"/>
    
      <xsl:template match="/">
          <html>
              <head>
                  <title>Grouping example</title>
              </head>
              <body>
                  <xsl:apply-templates/>
              </body>
          </html>
      </xsl:template>
    
      <xsl:template match="StudentData">
          <table>
              <thead>
                  <tr>
                      <th>Student Requisition</th>
                      <th>Student Test</th>
                      <th>Male Pass</th>
                      <th>Male Fail</th>
                      <th>Female Pass</th>
                      <th>Female Fail</th>
                  </tr>
              </thead>
              <tbody>
                  <xsl:for-each-group select="StudentRecord" composite="yes" group-by="StudentRequisition/@xd:Descriptor, ProfileStudentTestGroup/StudentTest/@xd:Descriptor">
                      <tr>
                          <td>{current-grouping-key()[1]}</td>
                          <td>{current-grouping-key()[2]}</td>
                          <td>{count(current-group()[Gender/@xd:Descriptor = 'Male'][ProfileStudentTestGroup/StudentTest_Status[@xd:Descriptor = 'Pass']])}</td>
                          <td>{count(current-group()[Gender/@xd:Descriptor = 'Male'][ProfileStudentTestGroup/StudentTest_Status[@xd:Descriptor = 'Fail']])}</td>
                          <td>{count(current-group()[Gender/@xd:Descriptor = 'Female'][ProfileStudentTestGroup/StudentTest_Status[@xd:Descriptor = 'Pass']])}</td>
                          <td>{count(current-group()[Gender/@xd:Descriptor = 'Female'][ProfileStudentTestGroup/StudentTest_Status[@xd:Descriptor = 'Fail']])}</td>
                      </tr>
                  </xsl:for-each-group>
              </tbody>
          </table>
      </xsl:template>
    
    </xsl:stylesheet>
    

    https://xsltfiddle.liberty-development.net/93dFepD

    If you use an XSLT 2 processor (which doesn't support a composite grouping key) then either concat the two values or nest two for-each-group instructions.