XSL duplicate info problem - xslt

Just trying out xsl and I've got one problem that just won't go away. My style sheet code is this
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="Fighter">
<br/>
<br/>
<br/>
<b>Name </b> <xsl:value-of select="name"/> <br/>
<b>AKA</b> <xsl:value-of select="nickname"/> <br/>
<b>Age</b> <xsl:value-of select="age"/> <br/>
<b>Height</b> <xsl:value-of select="height"/> <br/>
<b>Division</b> <xsl:value-of select="division"/> <br/>
<b>Reach</b> <xsl:value-of select="reach"/> <br/>
<b>Stance</b> <xsl:value-of select="stance"/> <br/>
<b>Nationality</b> <xsl:value-of select="nationality"/> <br/>
<b>Training Camp</b> <xsl:value-of select="camp"/> <br/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="bout">
<table width="100%" border="1">
<tr>
<td width ="10%"><xsl:value-of select="result"/></td>
<td width ="10%"><xsl:value-of select="opponent"/></td>
<td width ="10%"><xsl:value-of select="waywon"/></td>
<td width ="10%"><xsl:value-of select="round"/></td>
<td width ="10%"><xsl:value-of select="event"/></td>
<td width ="10%"><xsl:value-of select="date"/></td>
<td width ="10%"><xsl:value-of select="location"/></td>
<td width ="10%"><xsl:value-of select="notes"/></td>
</tr>
</table>
</xsl:template>
<xsl:template match="/">
<h1>LIST OF UFC FIGHTERS</h1>
<xsl:apply-templates/>
</xsl:template>
</xsl:transform>
I want to get some info on a fighter displed and then show the fight record as below. however it keeps on adding an extra line, as below.
Name George St Pierre AKA GSP Age 30 Height 5ft 10
in Division Welterweight Reach 76 in Stance
Orthodox Nationality Canadian Training Camp Tristar Gym
George St Pierre GSP 30 5ft 10 in Welterweight 76 in Orthodox Canadian
Tristar Gym
Why is this info printing out twice? I'm sure this is probably simple but it's really frustrating me.

Because you have apply-templates in template Fighter and no template for name, nickname, age etc - so XSL just copies text contented in this nodes - put this in the end of your XSL to avoid this and keep apply-templates there
<xsl:template match="*"></xsl:template>
This will put empty string for any tag not processed by other template

try this
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="Fighter">
<br/>
<br/>
<br/>
<b>Name </b> <xsl:value-of select="name"/> <br/>
<b>AKA</b> <xsl:value-of select="nickname"/> <br/>
<b>Age</b> <xsl:value-of select="age"/> <br/>
<b>Height</b> <xsl:value-of select="height"/> <br/>
<b>Division</b> <xsl:value-of select="division"/> <br/>
<b>Reach</b> <xsl:value-of select="reach"/> <br/>
<b>Stance</b> <xsl:value-of select="stance"/> <br/>
<b>Nationality</b> <xsl:value-of select="nationality"/> <br/>
<b>Training Camp</b> <xsl:value-of select="camp"/> <br/>
</xsl:template>
<xsl:template match="bout">
<table width="100%" border="1">
<tr>
<td width ="10%"><xsl:value-of select="result"/></td>
<td width ="10%"><xsl:value-of select="opponent"/></td>
<td width ="10%"><xsl:value-of select="waywon"/></td>
<td width ="10%"><xsl:value-of select="round"/></td>
<td width ="10%"><xsl:value-of select="event"/></td>
<td width ="10%"><xsl:value-of select="date"/></td>
<td width ="10%"><xsl:value-of select="location"/></td>
<td width ="10%"><xsl:value-of select="notes"/></td>
</tr>
</table>
</xsl:template>
<xsl:template match="/">
<h1>LIST OF UFC FIGHTERS</h1>
<xsl:apply-templates select="Fighter"/>
<xsl:apply-templates select="bout"/>
</xsl:template>
</xsl:transform>

Related

XSL Repeat Template Object containing List<Object>

I have a Library object that contains a collection of Books... The Library object has properties like Name, Address, Phone... While the Book object has properties like ISDN, Title, Author, and Price.
XML looks something like this...
<Library>
<Name>Metro Library</Name>
<Address>1 Post Rd. Brooklyn, NY 11218</Address>
<Phone>800 976-7070</Phone>
<Books>
<Book>
<ISDN>123456789</ISDN>
<Title>Fishing with Luke</Title>
<Author>Luke Miller</Author>
<Price>18.99</Price>
</Book>
<Book>
<ISDN>234567890</ISDN>
<Title>Hunting with Paul</Title>
<Author>Paul Worthington</Author>
<Price>28.99</Price>
</Book>
...
And more books
...
</Books>
</Library>
I have a template with space for only 10 per page for example. There can be hundreds of books in the list of Books... So I need to limit the number of books and repeat the template every 10 books.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<div>
<table>
<tr>
<td>NAME</td>
<td><xsl:value-of select="/Library/Name"/></td>
</tr>
<tr>
<td>ADDRESS</td>
<td><xsl:value-of select="/Library/Address"/></td>
</tr>
<tr>
<td>PHONE</td>
<td><xsl:value-of select="/Library/Phone"/></td>
</tr>
</table>
<table>
<xsl:for-each select="/Library/Books/Book">
<tr>
<td><xsl:value-of select="position()"/></td>
<td><xsl:value-of select="ISDN"/></td>
<td><xsl:value-of select="Title"/></td>
<td><xsl:value-of select="Author"/></td>
<td><xsl:value-of select="Price"/></td>
</tr>
</xsl:for-each>
</table>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
How can I get the Library information to appear on all repeating pages and add 10 books per page?... First page has Library info with Books 1 thru 10, Second page has Library info with Books 11 thru 20, and so on??
Thanks
For starters, try not to use for-each, apply-templates allows the engine to optimise the order that events are processed.
It appears that you are calling this stylesheet from some other system, so the approach I've taken is to define a pagination param. In the host language, when you call this just change the root parameter. This then allows you to select the require pages in this line here:
Books/Book[($page - 1)*10 < position() and position() <= ($page)*10]
This should do the trick.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="page" select="1"/>
<xsl:template match="/Library">
<html>
<body>
<div>
<table>
<tr>
<td>NAME</td>
<td>
<xsl:value-of select="/Name"/>
</td>
</tr>
<tr>
<td>ADDRESS</td>
<td>
<xsl:value-of select="/Address"/>
</td>
</tr>
<tr>
<td>PHONE</td>
<td>
<xsl:value-of select="/Phone"/>
</td>
</tr>
</table>
<table>
<xsl:apply-templates select="Books/Book[($page - 1)*10 < position() and position() <= ($page)*10]"/>
</table>
</div>
</body>
</html>
</xsl:template>
<xsl:template match="/Book">
<tr>
<td>
<xsl:value-of select="position()"/>
</td>
<td>
<xsl:value-of select="ISDN"/>
</td>
<td>
<xsl:value-of select="Title"/>
</td>
<td>
<xsl:value-of select="Author"/>
</td>
<td>
<xsl:value-of select="Price"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>

Two-column tables using XSLT

Here is a fraction of the XML data I am processing
<?xml version="1.0" encoding="utf-16"?>
<ScorecardSummary>
<DivisionSummary>
<DivisionName>
<string> SYSTEM</string>
</DivisionName>
<ScorecardSummaryByDivision>
<ScorecardSummaryByKPI>
<Header>
<string>Committed Time of Arrival</string>
<string>Goal</string>
<string>1D</string>
<string>7D</string>
<string>QTD</string>
<string>YTD</string>
<string>YTD Event Cars</string>
</Header>
<Data>
<ScorecardContract>
<TypeName>System</TypeName>
<Goal>68</Goal>
<GoalWarning>64.6</GoalWarning>
<TotalCountYear>1234</TotalCountYear>
<Value1D>79</Value1D>
<Value7D>79.2</Value7D>
<ValueQTD>79.1</ValueQTD>
<ValueYTD>73.3</ValueYTD>
</ScorecardContract>
<ScorecardContract>
<TypeName>AG</TypeName>
<Goal>68</Goal>
<GoalWarning>64.6</GoalWarning>
<TotalCountYear>1111</TotalCountYear>
<Value1D>80.9</Value1D>
<Value7D>78.7</Value7D>
<ValueQTD>78.4</ValueQTD>
<ValueYTD>69.7</ValueYTD>
</ScorecardContract>
This is a small part of the XSL that produces the tables:
<xsl:template match="ScorecardSummary/DivisionSummary/DivisionName">
<h1>
<xsl:value-of select="current()/string"/>
</h1>
</xsl:template>
<xsl:template match="ScorecardSummaryByDivision">
<xsl:apply-templates select="current()/ScorecardSummaryByKPI"/>
</xsl:template>
<xsl:template match="ScorecardSummaryByKPI">
<table border="1" cellspacing="0" cellpadding="5">
<tr>
<xsl:choose>
<xsl:when test="count(preceding-sibling::ScorecardSummaryByKPI) mod 6 < 4">
<td>
<table border="1" cellspacing="0" cellpadding="5">
<xsl:apply-templates select="Header"/>
<xsl:apply-templates select="Data"/>
</table>
</td>
</xsl:when>
<xsl:otherwise>
<td>
<table border="1" cellspacing="0" cellpadding="5">
<xsl:apply-templates select="Header"/>
<xsl:apply-templates select="Data"/>
</table>
</td>
</xsl:otherwise>
</xsl:choose>
</tr>
</table>
</xsl:template>
The XSL produces 6 tables repeatedly like this:
1
2
3
4
5
6
1
2
3
4
5
6
But I want to order them like this:
1 4
2 5
3 6
1 4
2 5
3 6
and so on. I tried using this check, but it doesn't work.
count(preceding-sibling::ScorecardSummaryByKPI) mod 6 < 4
Can anyone help?
Explanation
Your table must have two <td> per row (if you want two columns). Your XSLT does generate only one.
Solution is to interate over one half of the list and generate two <td> per iteration.
So first I would define a size of the table. Example:
<xsl:param name="size" select="count(catalog/cd)"/>
Then iterate over only a half of it ($size div 2). The number must be rounded if the input list can contain a non-even number of elements: ceiling($size div 2) (Rounding up to catch last element)
<xsl:for-each select="catalog/cd[ceiling($size div 2) >= position()]">
In each iteration, first render an element itself:
<td><xsl:value-of select="title"/></td>
Then render an appropriate element from the second half of the table (offset is the number defined before: ceiling($size div 2) Half size of the table)
<td><xsl:value-of select="following::cd[ceiling($size div 2)]/title"/></td>
You can wrap element rendering in a separate template to avoid code repeating.
Working example
Check this transformation example with W3C XSL TryIt (http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog):
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:param name="size" select="count(catalog/cd)"/>
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Title</th>
</tr>
<xsl:for-each select="catalog/cd[ceiling($size div 2) >= position()]">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="following::cd[ceiling($size div 2)]/title"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
It splits CD-catalog (given in example link above) in two columns.
Perhaps something like this is what you are looking for:
(This only shows the idea, you have to adapt it to your input.)
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/" >
<xsl:apply-templates select="//t[count(preceding-sibling::t) < 3]" mode="tables" />
</xsl:template>
<xsl:template match="t" >
{<xsl:value-of select="text()"/>}
</xsl:template>
<xsl:template match="t" mode="tables">
<table border="1">
<tr>
<td>
<table border="1" >
<xsl:apply-templates select="." />
</table>
</td>
<td>
<table border="1">
<xsl:apply-templates select="following-sibling::t[count(preceding-sibling::t) = count(current()/preceding-sibling::t) +3]" />
</table>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
With this short test input xml:
<?xml version="1.0" encoding="utf-8"?>
<xml>
<tables>
<t>1</t>
<t>2</t>
<t>3</t>
<t>4</t>
<t>5</t>
<t>6</t>
</tables>
</xml>
It will generate this output:
<?xml version="1.0"?>
<table xmlns="http://www.w3.org/1999/xhtml" border="1">
<tr>
<td>
<table border="1">
{1}
</table>
</td>
<td>
<table border="1">
{4}
</table>
</td>
</tr>
</table><table xmlns="http://www.w3.org/1999/xhtml" border="1">
<tr>
<td>
<table border="1">
{2}
</table>
</td>
<td>
<table border="1">
{5}
</table>
</td>
</tr>
</table><table xmlns="http://www.w3.org/1999/xhtml" border="1">
<tr>
<td>
<table border="1">
{3}
</table>
</td>
<td>
<table border="1">
{6}
</table>
</td>
</tr>
</table>

The variable or parameter 'Rows' is either not defined or it is out of scope

How do i achieve this through xslt?
I am getting an error from the cde above given by you
( sharepoint 2010 xslt dataview : modify table structure to display list item )
The error is: The variable or parameter 'Rows' is either not defined or it is out of scope.
Please help why am i getting this error:(
My full code would go like this after the code by you has been added:
<xsl:template match='dsQueryResponse'>
<table cellpadding="10" cellspacing="0" border="1" style="padding:25px;">
<!--table for head-->
<tr>
<!--table row-->
<td colspan='2'>
<!--table definition-->
<b style="font-size:25px;">ELearning List</b>
<!-- heading-->
</td>
</tr>
<xsl:apply-templates select='Rows/Row'/>
</table>
</xsl:template>
<xsl:template match='Row'>
<!-- template is defined above -->
<xsl:for-each select="$Rows[position() mod 3 = 1]">
<!-- 3 recods in one row should be displayed -->
<tr>
<xsl:variable name="i" select="position() - 1" />
<xsl:for-each select="$Rows[(position() > ($i * 3)) and (position() <= (($i + 1) * 3))]">
<td>
<img src="../PublishingImages/FLDRNEW.GIF" width="50px" height="50px" style="padding-right:20px;"></img>
<!-- image is to display folder below which the hyperlinked text has been populated -->
<br/>
<a href="{#FileRef}" style="font-weight:bold;">
<!-- it is the anchor tag which drives to the corresponding documents -->
<xsl:value-of select="substring-after(string(#FileRef),'/Docs/')"/>
<!-- fetches the value of Name column -->
</a>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</xsl:template>
The error is: The variable or parameter 'Rows' is either not defined or it is out of scope.
Please help
Could you give this a try?
<xsl:template match='dsQueryResponse'>
<table cellpadding="10" cellspacing="0" border="1" style="padding:25px;">
<!--table for head-->
<tr>
<!--table row-->
<td colspan='2'>
<!--table definition-->
<b style="font-size:25px;">ELearning List</b>
<!-- heading-->
</td>
</tr>
<xsl:apply-templates
select='Rows/Row[position() mod 3 = 1]' mode="group" />
</table>
</xsl:template>
<xsl:template match='Row' mode="group">
<tr>
<xsl:apply-templates
select=". | following-sibling::Row[position() < 3]" />
</tr>
</xsl:template>
<xsl:template match="Row">
<td>
<!-- image is to display folder below which the hyperlinked text has
been populated -->
<img src="../PublishingImages/FLDRNEW.GIF" width="50px" height="50px"
style="padding-right:20px;" />
<br/>
<!-- the anchor tag which drives to the corresponding documents -->
<a href="{#FileRef}" style="font-weight:bold;">
<!-- fetches the value of Name column -->
<xsl:value-of select="substring-after(string(#FileRef),'/Docs/')"/>
</a>
</td>
</xsl:template>

Extracting the attributes when the occurance of them is not particular

I am working on the extracting the values background color and width attributes from "td" of a table.
There are several ways of occurance of Back ground color and width. T
I have following set of valid elements.
1.<td style="BACKGROUND-COLOR: yellow; WIDTH: 52%"></td>
(combination of BACKGROUND-COLOR and Width in one order)
2.<td style="WIDTH: 52%;BACKGROUND-COLOR: green"></td>
(combination of BACKGROUND-COLOR and Width in another order)
3.<td style="WIDTH:52%;BACKGROUND-COLOR: green"></td>
(Spaces could vary from ":" and value)
4.<td style="BACKGROUND-COLOR: gray"></td>
(only BACKGROUND-COLOR in style)
5.<td style="BACKGROUND-COLOR: Gray"></td>
(Value of BACKGROUND-COLOR can be case sensitive)
6.<td style="BACKGROUND-COLOR: #ffff00"></td>
(value of BACKGROUND-COLOR can be hexadecimal also)
7.<td bgcolor="#008000" style="WIDTH: 54%">
(BACKGROUND-COLOR can occur as bgcolr also(hexadecimal code)
8.<td bgcolor="yellow">
(BACKGROUND-COLOR can occur as bgcolr also(string))
List of valid colors and their codes:(all the values are case sensitive)
Yellow:#ffff00
Gray:#808080
Green:#008000
Output:
1.<bgclr>Yellow</bgclr>
<colwidth>52</colwidth>
2.<bgclr>Green</bgclr>
<colwidth>52</colwidth>
3. <bgclr>Green</bgclr>
<colwidth>52</colwidth>
4.<bgclr>Gray</bgclr>
5.<bgclr>Gray</bgclr>
6.<bgclr>Yellow</bgclr>
7.<bgclr>Green</bgclr>
<colwidth>54</colwidth>
8.<bgclr>Yellow</bgclr>
I have tried my level best to solve this, and it looks complicated for me.
I am also providing the valid xml file.
<tr>
<td style="BACKGROUND-COLOR: yellow; WIDTH: 52%"></td>
<td style="WIDTH: 52%;BACKGROUND-COLOR: green"></td>
<td style="WIDTH:52%;BACKGROUND-COLOR: green"></td>
<td style="BACKGROUND-COLOR: gray"></td>
<td style="BACKGROUND-COLOR: Gray"></td>
<td style="BACKGROUND-COLOR: #ffff00"></td>
<td bgcolor="#008000" style="WIDTH: 54%"></td>
<td bgcolor="yellow"></td>
</tr>
Can any one help on this.
Thanks.
We can leverage the power of xsl:apply-templates and predicates to avoid a lot of painful xsl:choose statements. A template approach will also give us a more modular solution.
This XSLT 1.0 style-sheet ...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:template match="/">
<tr>
<xsl:apply-templates select="*/td"/>
</tr>
</xsl:template>
<xsl:template match="td">
<td>
<xsl:apply-templates
select="self::*[contains(#style,'BACKGROUND-COLOR:') or #bgcolor]"
mode="bg-colour"/>
<xsl:apply-templates
select="self::*[contains(#style,'WIDTH:')]"
mode="width"/>
</td>
</xsl:template>
<xsl:template match="td[#bgcolor]" mode="bg-colour">
<xsl:call-template name="render-bg-colour">
<xsl:with-param name="raw-colour" select="#bgcolor" />
</xsl:call-template>
</xsl:template>
<xsl:template match="td" mode="bg-colour">
<xsl:call-template name="render-bg-colour">
<xsl:with-param name="raw-colour" select="
substring-before( substring-after(concat(#style,';'),'BACKGROUND-COLOR:'), ';')" />
</xsl:call-template>
</xsl:template>
<xsl:variable name="palette">
<colours>
<colour>
<code>#ffff00</code>
<name>Yellow</name>
</colour>
<colour>
<code>#808080</code>
<name>Gray</name>
</colour>
<colour>
<code>#008000</code>
<name>Green</name>
</colour>
</colours>
</xsl:variable>
<xsl:template name="render-bg-colour">
<xsl:param name="raw-colour" />
<xsl:variable name="trim-colour" select="normalize-space( $raw-colour)" />
<xsl:variable name="canon-colour" select="
document('')//xsl:variable[#name='palette']/colours/colour[
(translate($trim-colour, $uppercase, $lowercase) =
translate(name , $uppercase, $lowercase) ) or
($raw-colour = code)
]/name/text()"/>
<bgclr>
<xsl:value-of select="$canon-colour" />
</bgclr>
</xsl:template>
<xsl:template match="td" mode="width">
<colwidth>
<xsl:value-of select="
normalize-space( substring-before( substring-after(#style,'WIDTH:'), '%'))" />
</colwidth>
</xsl:template>
</xsl:stylesheet>
... when applied to this input document ...
<tr>
<td style="BACKGROUND-COLOR: yellow; WIDTH: 52%"></td>
<td style="WIDTH: 52%;BACKGROUND-COLOR: green"></td>
<td style="WIDTH:52%;BACKGROUND-COLOR: green"></td>
<td style="BACKGROUND-COLOR: gray"></td>
<td style="BACKGROUND-COLOR: Gray"></td>
<td style="BACKGROUND-COLOR: #ffff00"></td>
<td bgcolor="#008000" style="WIDTH: 54%"></td>
<td bgcolor="yellow"></td>
</tr>
... will yield this output document...
<tr>
<td>
<bgclr>Yellow</bgclr>
<colwidth>52</colwidth>
</td>
<td>
<bgclr>Green</bgclr>
<colwidth>52</colwidth>
</td>
<td>
<bgclr>Green</bgclr>
<colwidth>52</colwidth>
</td>
<td>
<bgclr>Gray</bgclr>
</td>
<td>
<bgclr>Gray</bgclr>
</td>
<td>
<bgclr>Yellow</bgclr>
</td>
<td>
<bgclr>Green</bgclr>
<colwidth>54</colwidth>
</td>
<td>
<bgclr>Yellow</bgclr>
</td>
</tr>

XSL sum() and variable/loop

I have been trying to figure out why my variable assigned sum isn't working, also my table output is repeating only the first element through out the whole table. What i am trying to get this code to do is get the studentID of each student printed in the first column, the student name of that ID in the second column, and then assign a variable that holds the students total mark of the 3 assessments they have completed to print their total mark in the third column, followed by as assignment of HD, D, C, P, or F as based on their total mark e.g. HD is 85 plus and D is 75+ but not higher than 84. etc.
Can someone tell me where I am going wrong? I am still new to XML/XSL so criticism is welcome.
grade.xsl
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="StudentAmount" select="count(document('AssessmentItems.xml')/assessmentList/unit/studentList/student)"/>
<xsl:variable name="totalmark" select="sum(document('AssessmentItems.xml')/assessmentList/unit/*
[//assessmentList/unit/assessmentItems/assessment/#studId = //assessmentList/unit/studentList/student/#sid])"/>
<html>
<body>
<h2>Grade Report for <xsl:value-of select="assessmentList/unit/#unitId"/> - <xsl:value-of select="assessmentList/unit/unitName"/></h2>
<p>Number of students in this unit: <xsl:value-of select="$StudentAmount"/></p>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Total Mark</th>
<th>Grade</th>
</tr>
<xsl:for-each select="assessmentList/unit/studentList/student">
<tr>
<td><xsl:value-of select="document('AssessmentItems.xml')/assessmentList/unit/studentList/student/#sid"/></td>
<td><xsl:value-of select="document('AssessmentItems.xml')/assessmentList/unit/studentList/student"/></td>
<td><xsl:value-of select="document('AssessmentItems.xml')/assessmentList/unit/assessmentItems/assessment/mark"/></td>
<xsl:choose>
<xsl:when test="$totalmark > 85">
<td color="blue">HD</td>
</xsl:when>
<xsl:when test="$totalmark > 75">
<td color="black">D</td>
</xsl:when>
<xsl:when test="$totalmark > 65">
<td color="black">C</td>
</xsl:when>
<xsl:when test="$totalmark > 50">
<td color="black">P</td>
</xsl:when>
<xsl:otherwise>
<td color="red">F</td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
and this is the file AssessmentItems.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="grade.xsl"?>
<assessmentList>
<unit unitId="3311">
<unitName>Learn To Read</unitName>
<studentList>
<student sid="1001">Lisa Simpson</student>
<student sid="1002">Barney Rubble</student>
<student sid="1003">Donald Duck</student>
</studentList>
<assessmentItems>
<assessment name="Assignment 1" weight="20">
<mark studId="1001">12</mark>
<mark studId="1002">18</mark>
<mark studId="1003">9</mark>
</assessment>
<assessment name="Assignment 2" weight="25">
<mark studId="1001">23</mark>
<mark studId="1002">14</mark>
<mark studId="1003">12.5</mark>
</assessment>
<assessment name="Quiz" weight="15">
<mark studId="1001">13</mark>
<mark studId="1002">9</mark>
<mark studId="1003">6</mark>
</assessment>
<assessment name="Final Exam" weight="40">
<mark studId="1001">38</mark>
<mark studId="1002">21</mark>
<mark studId="1003">20.5</mark>
</assessment>
</assessmentItems>
</unit>
</assessmentList>
Firstly, because you are only working on a single XML document, you don't need the constant references to document('AssessmentItems.xml') at all. So, for example
<xsl:value-of
select="document('AssessmentItems.xml')/assessmentList/unit/studentList/student/#sid"/>
Can be replaced with just
<xsl:value-of select="/assessmentList/unit/studentList/student/#sid"/>
This leads on to the second problem. The xpath above is relative to the document element of the XML and will return the #sid of the very first student it finds, and no the #sid of the student you are currently positioned on. You can simply do this in your case
<xsl:value-of select="#sid"/>
Another issue is that you define the variable totalmarks at the top of the XSLT, when in fact it should be defined within the scope of your xsl:for-each so that it is specific for the current student
<xsl:variable name="totalmark" select="sum(../../assessmentItems/assessment/mark[#studId = current()/#sid])" />
Actually, it may be better to make use of a key here, to look up the results
<xsl:key name="marks" match="mark" use="#studId" />
And to get the total results for a student....
<xsl:variable name="totalmark" select="sum(key('marks', #sid))" />
One final comment, although not a problem, it is often better to use xsl:apply-templates rather than xsl:for-each as this avoids excessive indentation, and allows better code re-use.
Try the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="marks" match="mark" use="#studId"/>
<xsl:template match="/">
<xsl:variable name="StudentAmount" select="count(/assessmentList/unit/studentList/student)"/>
<html>
<body>
<h2>Grade Report for
<xsl:value-of select="assessmentList/unit/#unitId"/>-
<xsl:value-of select="assessmentList/unit/unitName"/>
</h2>
<p>Number of students in this unit:
<xsl:value-of select="$StudentAmount"/></p>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Total Mark</th>
<th>Grade</th>
</tr>
<xsl:apply-templates select="assessmentList/unit/studentList/student"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="student">
<xsl:variable name="totalmark" select="sum(key('marks', #sid))"/>
<tr>
<td>
<xsl:value-of select="#sid"/>
</td>
<td>
<xsl:value-of select="."/>
</td>
<td>
<xsl:value-of select="$totalmark"/>
</td>
<xsl:choose>
<xsl:when test="$totalmark > 85">
<td color="blue">HD</td>
</xsl:when>
<xsl:when test="$totalmark > 75">
<td color="black">D</td>
</xsl:when>
<xsl:when test="$totalmark > 65">
<td color="black">C</td>
</xsl:when>
<xsl:when test="$totalmark > 50">
<td color="black">P</td>
</xsl:when>
<xsl:otherwise>
<td color="red">F</td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:template>
</xsl:stylesheet>
When applied to your XML, the following HTML is output
<html>
<body>
<h2>Grade Report for 3311- Learn To Read</h2>
<p>Number of students in this unit: 3</p>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Total Mark</th>
<th>Grade</th>
</tr>
<tr>
<td>1001</td>
<td>Lisa Simpson</td>
<td>86</td>
<td color="blue">HD</td>
</tr>
<tr>
<td>1002</td>
<td>Barney Rubble</td>
<td>62</td>
<td color="black">P</td>
</tr>
<tr>
<td>1003</td>
<td>Donald Duck</td>
<td>48</td>
<td color="red">F</td>
</tr>
</table>
</body>
</html>
Do note this assumes only one unit element in your XML. If your actual XML have multiple units, and you wanted a separate table for each, then this is not a problem, you would just need to make sure the unit id is part of the xsl:key so you can look up results for a given student in a given unit.
A very quick glance at your code reveals that the predicate
[//assessmentList/unit/assessmentItems/assessment/#studId = //assessmentList/unit/studentList/student/#sid]
is obviously wrong, because it has the same value (either true or false) for every element in your source document.
Correcting it requires more study of the problem than I have time for. But you seem to have fallen victim to the "if it doesn't work then put '//' at the front" fallacy.