Generating a calendar using XSLT
Posted: 16 November 2008
Recently I was tasked to build an interactive calendar in XSLT. I wanted the calendar to always start on a Sunday as well as have clean markup. I couldn't find any good examples on the web while I was building it, so I decided to post the base of my solution.
Insert the following variables and templates into your stylesheet:
<xsl:variable name="DisplayDate" select="date:date()"/>
<xsl:variable name="Year" select="date:year($DisplayDate)"/>
<xsl:variable name="Month" select="date:month-in-year($DisplayDate)"/>
<xsl:variable name="MonthName" select="date:month-name($DisplayDate)" />
<xsl:variable name="NumberOfDaysInMonth">
<xsl:call-template name="DaysInMonth">
<xsl:with-param name="month" select="$Month" />
<xsl:with-param name="year" select="$Year" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="FirstDayInWeekForMonth" select="date:day-in-week(date:date(concat($Year,'-', $Month, '-01')))" />
<xsl:variable name="WeeksInMonth"><xsl:value-of select="($NumberOfDaysInMonth + $FirstDayInWeekForMonth - 1) div 7" /></xsl:variable>
<xsl:template name="DaysInMonth">
<xsl:param name="month"><xsl:value-of select="$Month" /></xsl:param>
<xsl:param name="year"><xsl:value-of select="$Year" /></xsl:param>
<xsl:choose>
<xsl:when test="$month = 1 or $month = 3 or $month = 5 or $month = 7 or $month = 8 or $month = 10 or $month = 12">31</xsl:when>
<xsl:when test="$month=2">
<xsl:choose>
<xsl:when test="$year mod 4 = 0">29</xsl:when>
<xsl:otherwise>28</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>30</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="Calendar">
<table summary="Monthly calendar">
<caption>
<xsl:value-of select="$MonthName" />
<xsl:text> </xsl:text>
<xsl:value-of select="$Year" />
</caption>
<tr>
<th abbr="Sunday">Sun</th>
<th abbr="Monday">Mon</th>
<th abbr="Tuesday">Tue</th>
<th abbr="Wednesday">Wed</th>
<th abbr="Thursday">Thu</th>
<th abbr="Friday">Fri</th>
<th abbr="Saturday">Sat</th>
</tr>
<xsl:call-template name="CalendarWeek"/>
</table>
</xsl:template>
<xsl:template name="CalendarWeek">
<xsl:param name="week">1</xsl:param>
<xsl:param name="day">1</xsl:param>
<tr>
<xsl:call-template name="CalendarDay">
<xsl:with-param name="day" select="$day" />
</xsl:call-template>
</tr>
<xsl:if test="$WeeksInMonth > $week">
<xsl:call-template name="CalendarWeek">
<xsl:with-param name="week" select="$week + 1" />
<xsl:with-param name="day" select="$week * 7 - ($FirstDayInWeekForMonth - 2)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="CalendarDay">
<xsl:param name="count">1</xsl:param>
<xsl:param name="day" />
<xsl:choose>
<xsl:when test="($day = 1 and $count != $FirstDayInWeekForMonth) or $day > $NumberOfDaysInMonth">
<td class="empty"><xsl:text disable-output-escaping="yes">&nbsp;</xsl:text></td>
<xsl:if test="$count < 7">
<xsl:call-template name="CalendarDay">
<xsl:with-param name="count" select="$count + 1" />
<xsl:with-param name="day" select="$day" />
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:value-of select="$day" />
</td>
<xsl:if test="$count < 7">
<xsl:call-template name="CalendarDay">
<xsl:with-param name="count" select="$count + 1" />
<xsl:with-param name="day" select="$day + 1" />
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>For this code to work, you need to be using exslt.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
xmlns:date="http://exslt.org/dates-and-times">Once you have added the templates you can call the calendar like this:
<xsl:call-template name="Calendar" />Finally add some CSS to the page so your calendar looks more presentable:
<style type="text/css" media="screen">
table{
border:1px solid #CCC;
border-collapse: collapse;
}
caption{
font-weight:bold;
font-size:120%;
margin-bottom:8px;
}
td,th{
text-align:center;
vertical-align:middle;
width:36px;
height:34px;
border:1px solid #CCC;
padding:0;
}
th{
height:inherit;
}
.empty{
background-color:#EEE;
}
</style>
This is only the base of the calendar I built, and you can expand this to make it browse-able. But I will leave that for another post.
Post a comment
Comment Guidelines
- Have no more than 2 links, otherwise your comment will be flagged as spam.
- Links are automagically generated.
- <em>text</em> to make text italic.
- <strong>text</strong> to make text bold.
JavaScript needs to be enabled to comment.
Your comments
No comments have been made. Why not be the first?