xmlxsltmuenchian-grouping

Muenchian grouping, counting number of groups


Am using muenchian grouping to group subjets and grades as per students. I can get count for number of subjects opted by each student. But I could not get count of number of students.

Input XML

<data>
  <school>MIT Kindergarden</school>
  <year>2013</year>
  <batch>B</batch>
  <result>
    <student>ABC</student>
    <id>001</id>
    <subject>ALG</subject>
    <grade>C</grade>
  </result>
  <result>
    <student>ABC</student>
    <id>001</id>
    <subject>HIS</subject>
    <grade>B</grade>
  </result>
  <result>
    <student>XYZ</student>
    <id>002</id>
    <subject>ALG</subject>
    <grade>C</grade>
  </result>
  <result>
    <student>XYZ</student>
    <id>002</id>
    <subject>ALG</subject>
    <grade>A</grade>
  </result>
</data>

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="group-by-id" match="data/result" use="id" />

  <xsl:template match="/">
    <schoolresult>
      <schoolname><xsl:value-of select="data/school" /></schoolname>
      <resultyear><xsl:value-of select="data/year" /></resultyear>
      <batch><xsl:value-of select="data/batch" /></batch>
      <totalstudent>[Could not find]</totalstudent>
      <xsl:for-each select="data/result[generate-id() = generate-id(key('group-by-id', id)[1])]">
        <student>
          <info>
            <name><xsl:value-of select="student" /></name>
            <id><xsl:value-of select="id" /></id>
            <subjectsopted>
              <xsl:value-of select="count(. | key('group-by-id', id))" />
            </subjectsopted>
          </info>
          <xsl:for-each select="key('group-by-id', id)">
            <subject>
              <name><xsl:value-of select="subject" /></name>
              <grade><xsl:value-of select="grade" /></grade>
            </subject>
          </xsl:for-each>
        </student>
      </xsl:for-each>
    </schoolresult>
  </xsl:template>
</xsl:stylesheet>

Output XML

<schoolresult>
  <schoolname>MIT Kindergarden</schoolname>
  <resultyear>2013</resultyear>
  <batch>B</batch>
  <studentscount>[Count not find]</studentscount>
  <student>
    <info>
      <name>ABC</name>
      <id>001</id>
      <subjectsopted>2</subjectsopted>
    </info>
    <subject>
      <name>ALG</name>
      <grade>C</grade>
    </subject>
    <subject>
      <name>HIS</name>
      <grade>B</grade>
    </subject>
  </student>
  <student>
    <info>
      <name>XYZ</name>
      <id>002</id>
      <subjectsopted>2</subjectsopted>
    </info>
    <subject>
      <name>ALG</name>
      <grade>C</grade>
    </subject>
    <subject>
      <name>ALG</name>
      <grade>A</grade>
    </subject>
  </student>
</schoolresult>

Solution

  • If you apply this XSLT to your source you will also get the students counted:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:key name="group-by-id" match="data/result" use="id" />
    
    <xsl:template match="/">
        <schoolresult>
            <schoolname><xsl:value-of select="data/school" /></schoolname>
            <resultyear><xsl:value-of select="data/year" /></resultyear>
            <batch><xsl:value-of select="data/batch" /></batch>
            <totalstudent>
                <xsl:variable name="studentNumber" select="data/result[generate-id() = generate-id(key('group-by-id', id)[1])]"/>
                <xsl:value-of select="count($studentNumber)"/>
            </totalstudent>
            <xsl:for-each select="data/result[generate-id() = generate-id(key('group-by-id', id)[1])]">
                <student>
                    <info>
                        <name><xsl:value-of select="student" /></name>
                        <id><xsl:value-of select="id" /></id>
                        <subjectsopted>
                            <xsl:value-of select="count(. | key('group-by-id', id))" />
                        </subjectsopted>
                    </info>
                    <xsl:for-each select="key('group-by-id', id)">
                        <subject>
                            <name><xsl:value-of select="subject" /></name>
                            <grade><xsl:value-of select="grade" /></grade>
                        </subject>
                    </xsl:for-each>
                </student>
            </xsl:for-each>
        </schoolresult>
    </xsl:template>
    </xsl:stylesheet>
    

    The output looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <schoolresult>
    <schoolname>MIT Kindergarden</schoolname>
    <resultyear>2013</resultyear>
    <batch>B</batch>
    <totalstudent>2</totalstudent>
    <student>
        <info>
            <name>ABC</name>
            <id>001</id>
            <subjectsopted>2</subjectsopted>
        </info>
        <subject>
            <name>ALG</name>
            <grade>C</grade>
        </subject>
        <subject>
            <name>HIS</name>
            <grade>B</grade>
        </subject>
    </student>
    <student>
        <info>
            <name>XYZ</name>
            <id>002</id>
            <subjectsopted>2</subjectsopted>
        </info>
        <subject>
            <name>ALG</name>
            <grade>C</grade>
        </subject>
        <subject>
            <name>ALG</name>
            <grade>A</grade>
        </subject>
    </student>
    </schoolresult>
    

    All I did was added a variable studentNumber using your already defined key and counting that:

        <totalstudent>
                <xsl:variable name="studentNumber" select="data/result[generate-id() = generate-id(key('group-by-id', id)[1])]"/>
                <xsl:value-of select="count($studentNumber)"/>
            </totalstudent>