Krishna Chaitanya
Krishna Chaitanya

Reputation: 383

How to increment variable by 1 in xslt?

Consider a case I have to get the count of passed students, he is considered passed if he passes all the exams.

<testResults version="1.2">
<student test="1" pass="true" name="A"></student>
<student test="2" pass="true" name="A"></student>
<student test="1" pass="false" name="B"></student>
<student test="2" pass="true" name="B"></student>
<student test="1" pass="false" name="C"></student>
<student test="2" pass="false" name="C"></student>
<student test="1" pass="true" name="D"></student>
<student test="2" pass="true" name="D"></student>
</testResults>

I want to get the count of students who passed all subjects. How do I do that? I got a method where I iterate through all the students and display who passed all but how do I get the count of all students.

I'm using ,

<xsl:for-each select="/testResults/student/[not(@name = preceding::*/@name)]">
<xsl:variable name="allFailureCount" select="count(/testResults/*[attribute::pass='false'][@tn = current()/@name])" />
<xsl:choose>
<xsl:when test="$allFailureCount &gt; 0"></xsl:when>
<xsl:otherwise><xsl:value-of select="@name" /></xsl:otherwise>
</xsl:choose>
</xsl:for-each>

Upvotes: 0

Views: 6783

Answers (2)

Tim C
Tim C

Reputation: 70648

What you need here is a count of the "distinct" of student names, for students who have passed all their exams. It would probably help if you defined a key to look up the tests

<xsl:key name="students" match="student" use="@name" />

Then, to get the distinct list of passing students, you can use distinct-values in XSLT 2.0

distinct-values(testResults/student[not(key('students', @name)/@pass='false')]/@name)

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="text" />

    <xsl:key name="students" match="student" use="@name" />

    <xsl:template match="/">
      <xsl:variable name="passedStudents" select="distinct-values(testResults/student[not(key('students', @name)/@pass='false')]/@name)" />

      <xsl:for-each select="$passedStudents">
          <xsl:text>Student </xsl:text><xsl:value-of select="." /><xsl:text>&#10;</xsl:text>
      </xsl:for-each>
      <xsl:text>Total </xsl:text>
      <xsl:value-of select="count($passedStudents)" />
    </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Artemy Vysotsky
Artemy Vysotsky

Reputation: 2734

Something like this may work

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" encoding="UTF-8" indent="yes" />
   <xsl:template match="/">
      <result>
         <xsl:variable name="prods" select="testResults/student/name" />
         <xsl:for-each select="$prods">
            <xsl:if test="generate-id() = generate-id($prods[. = current()][1])">
               <xsl:if test="count(/testResults/student[@pass ='true' and name=current()]) = 2">
                  <name>
                     <xsl:value-of select="." />
                  </name>
               </xsl:if>
            </xsl:if>
         </xsl:for-each>
      </result>
   </xsl:template>
</xsl:stylesheet>

Output

<result>
   <name>A</name>
   <name>D</name>
</result>

First it constructs list of unique names using approach from How to use XSLT to create distinct values - and then counts number of nodes that match 2 conditions - pass is true and name is equal current unique name. If count is equal to the number of tests (2 - I set it hard-coded) - the name is added to the output.

EDIT

To count names - you can store them into temp var and then use simple count

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" encoding="UTF-8" indent="yes" />
   <xsl:template match="/">
      <xsl:variable name="prods" select="testResults/student/name" />
      <xsl:variable name="passOne">
         <xsl:for-each select="$prods">
            <xsl:if test="generate-id() = generate-id($prods[. = current()][1])">
               <xsl:if test="count(/testResults/student[@pass ='true' and name=current()]) = 2">
                  <name>
                     <xsl:value-of select="." />
                  </name>
               </xsl:if>
            </xsl:if>
         </xsl:for-each>
      </xsl:variable>
      <xsl:value-of select="count($passOne/name)" />
   </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Related Questions