Sebastian
Sebastian

Reputation: 155

Modifying a XSLT XPATH code for a different output

I need to modify my XSLT code for a different output result. I need to output a table with the sigle, number of students and average.

Here's my XML code :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<?xml-stylesheet href="class.xsl" type="text/xsl" ?>
<university>
<student><sname>Charlie Parker</name>
<course sigle="INF8430" note="69" />
<course sigle="INF1030" note="65" />
<course sigle="INF1230" note="73" /></student>
<student><name>Miles Davis</name>
<course sigle="INF8430" note="65" />
<course sigle="INF1030" note="77" />
<course sigle="INF1230" note="83" /></student>
<student><name>John Coltrane</name>
<course sigle="INF9430" note="24" />
<course sigle="INF1030" note="64" />
<course sigle="INF1230" note="56" /></student>
<student><name>Charles Mingus</name>
<course sigle="INF8430" note="34" />
<course sigle="INF1230" note="89" /></student>
</university>

Here's my XSLT Code so far :

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/university">
<html>
<body>
<table border="1">
<tr>
<th>Name</th>
<th>Average</th>
</tr>
<xsl:for-each select="student">
<xsl:sort select="substring-after(name, ' ')"/>
<tr>
<td><xsl:value-of select="name" /></td>
<td><xsl:value-of select="sum(course/@note) div count(course)"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Here's what the output should look like :

Desired Table

Thanks a lot for your help!

Upvotes: 0

Views: 38

Answers (1)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22647

Your input document is not well-formed, please be careful when posting questions on Stackoverflow.

The standard approach to identify elements that are unique with respect to their content or one of their attributes is to use a key. The best explanation of this is still on Jeni Tennison's web page.

You could also consider using the round() function if there's too much precision in the average column.

XSLT Stylesheet

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

    <xsl:key name="course-sigle" match="course" use="@sigle"/>

    <xsl:template match="/university">
        <html>
            <body>
            <table border="1">
                <tr>
                    <th>Sigle</th>
                    <th>Number of Students</th>
                    <th>Average</th>
                </tr>
                <xsl:for-each select="student/course[count(. | key('course-sigle', @sigle)[1]) = 1]">

                    <xsl:variable name="count" select="count(key('course-sigle', @sigle))"/>
                    <tr>
                        <td>
                            <xsl:value-of select="@sigle"/>
                        </td>
                        <td>
                            <xsl:value-of select="$count"/>
                        </td>
                        <td>
                            <xsl:value-of select="sum(key('course-sigle', @sigle)/@note) div $count"/>
                        </td>
                    </tr>
                </xsl:for-each>
            </table>
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

HTML Output

<html>
   <body>
      <table border="1">
         <tr>
            <th>Sigle</th>
            <th>Number of Students</th>
            <th>Average</th>
         </tr>
         <tr>
            <td>INF8430</td>
            <td>3</td>
            <td>56</td>
         </tr>
         <tr>
            <td>INF1030</td>
            <td>3</td>
            <td>68.66666666666667</td>
         </tr>
         <tr>
            <td>INF1230</td>
            <td>4</td>
            <td>75.25</td>
         </tr>
         <tr>
            <td>INF9430</td>
            <td>1</td>
            <td>24</td>
         </tr>
      </table>
   </body>
</html>

Rendered HTML Output

Including the round function, the output looks like

enter image description here


Besides, if you are in charge of designing this XML document, note that some of the names in it are either incomprehensible ("sigle") or inappropriate given the context ("note"). Proper terms would be "signature" and "grade", or "score".

Upvotes: 1

Related Questions