Thuan Seah wrote:
Hi Thuan,
I rewrote your XML Input a little, as you need a grid of some sorts to make up a at least a skeleton of a timetable:
---timetable.xml--------------------------------------------------- <?xml version="1.0" encoding="ISO-8859-1"?> <?xml-stylesheet type="text/xsl" href="timetable.xsl"?> <timetable> <grid> <week> <day id="mo">Monday</day> <day id="tu">Tuesday</day> <day id="we">Wednesday</day> <day id="th">Thursday</day> <day id="fr">Friday</day> </week> <day> <time id="8">0800</time> <time id="10">1000</time> <time id="12">1200</time> <time id="14">1400</time> <time id="16">1600</time> </day> </grid> <TimetableItem day="th" time="12"> <CourseID>Math1005</CourseID> <Lesson>Lecture</Lesson> <Location> <Building>Copland</Building> <Room>Theatre</Room> </Location> </TimetableItem> <TimetableItem day="mo" time="12"> <CourseID>Bla</CourseID> <Lesson>Lecture</Lesson> <Location> <Building>bldg1</Building> <Room>room1</Room> </Location> </TimetableItem> </timetable>
The TimeTableItem changed obviously, now having attributes making it more easy to filter the right items for each grid-cell of the resulting table.
This is the XSL file I wrote, using nested for-each loops to generate the HTML table:
---timetable.xsl--------------------------------------------------- <?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="
http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl

utput method="html">
<xsl:template match="/timetable">
<html>
<head>
<title>Timetable</title>
</head>
<body>
<table border="1">
<tr>
<!-- The represents the which is not defined in XML an en ENTITY, but is needed by IE to render empty td's correctly --> <!-- making the table header row --> <td> </td> <xsl:for-each select="grid/week/day"> <td><xsl:value-of select="."/></td> </xsl:for-each> </tr> <!-- making the the content --> <xsl:for-each select="grid/day/time"> <xsl:variable name="time" select="@id"/> <tr> <td><xsl:value-of select="."/></td> <xsl:for-each select="../../week/day"> <xsl:variable name="day" select="@id"/> <td> <xsl:choose> <xsl:when test="count(/timetable/TimetableItem[@day=$day and @time=$time]) != 0"> <xsl:apply-templates select="/timetable/TimetableItem[@day=$day and @time=$time]"/> </xsl:when> <xsl

therwise> <!-- if there is nothing else, the must be written --> </xsl

therwise> </xsl:choose> </td> </xsl:for-each> </tr> </xsl:for-each> </table> </body> </html> </xsl:template>
<xsl:template match="TimetableItem">
<div><strong><xsl:value-of select="CourseID"/></strong></div> <div><xsl:value-of select="Lesson"/></div> <div> <em> <xsl:value-of select="Location/Building"/>, <xsl:value-of select="Location/Room"/> </em> </div> </xsl:template>
</xsl:stylesheet>
The XPath Expression
/timetable/TimetableItem[@day=$day and @time=$time]
selects exactly the one node for the day/time in question, or nothing.
If there is nothing for the specific day/time, an non-breaking space is needed (at least for IE) to display the empty table cell. I used the count function to test for that, but maybe there is a more efficient way, as in my solution the same XPath expression is executed twice in case there is at least one course.
But this is academic, as for such a small solution there is no performance impact one should worry about.
I hope I could help you,
Martin