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