Search
Web Braintrove
Site Navigation
Home
Products
Tags
Levels
Dates
Authors
5 MOST RECENT
Conditionally Display Different Values In a Single Expression Box
Create a Button With a Blank Label
Create Shared Rules
Perform a Case-Insensitive String Comparison without Using Translate()
Force a Field Value to a Boolean Using Rules
5 MOST POPULAR
Pass Query String Parameters to an ASP.NET Xml Control
Access a Method in a Master Page with Code-Behind
Prevent Namespace Prefixes from Being Copied to the Output
Create Groups in a Drop-Down List Box
Change the Default Action of the Power Button on the Windows Vista Start Menu
5 MOST FORGOTTEN
Hide Deleted Items in the Source Control Explorer
Recover a Dark Picture with a Heavy Color Cast
Prevent Windows Vista from Requesting Your Permission to Continue
Create a Variable with a Unique Sorted Node-Set
Prevent Users from Seeing ASP.NET Error Pages
Books
XPath 2.0 Programmer's Reference
Inside XSLT
HTML Utopia: Designing Without Tables Using CSS
Learning XSLT
Easy HTML-DB Oracle Application Express : Create Dynamic Web Pages with OAE
Magazines
Inside Web Design
Visual Studio Magazine
Asp.netpro
Web Site Management And Internet Advertising Trends
Practical Web Design
Microsoft MVP
This article has been viewed 699 times.

Group Dates by Year, Month and Day

Page 1 of 2
Written by Gregory Scot Collins
Thursday, 17 August 2006, 1:35 AM
This article has been tested to work with the following products and versions. No guarantee of compatibility, with or without modification, is offered for products or versions other than those listed.
When working with lists of date-oriented items, such as calendar events, birthdays, etc., it often becomes desirable to group list items by their date. This article focuses on grouping by date parts, but could easily be altered to group by any kind of data. We will present a short list of holiday calendar events grouped by year, month and then day.

Create the Events.xml file

We need a simple XML file to transform that contains our list of holiday calendar events. Copy the contents of Listing 1 into a text editor, and then save the file as Events.xml.

Create the Calendar.xsl file

Now we need a transform to group the list of holiday events by date. This transform will first identify a unique set of years from the event dates. Below each year we will display a unique set of months for that year, utilizing a named template to display the full name of the month. Below each month we could simply list event details preceded by the day, but instead we will once more group by a unique set of days before listing the event details.
Copy the contents of Listing 2 into a text editor, and then save the file as Calendar.xsl. Be sure to save it in the same folder as the Events.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
<xsl:output method="html" indent="no"/>
 
<xsl:template match="Events">
    <style>.indent {margin-left:20px;}</style>
    <div>Holiday Event Calendar:</div><br/>
    <xsl:apply-templates select="Event" mode="Year">
        <xsl:sort select="@date" data-type="text" order="ascending"/>
    </xsl:apply-templates>
</xsl:template>
 
<xsl:template match="Event" mode="Year">
    <xsl:if test="not(preceding-sibling::Event[substring(@date,1,4) = substring(current()/@date,1,4)])">
        <div><xsl:value-of select="substring(@date,1,4)"/></div>
        <div class="indent">
            <xsl:apply-templates select="../Event[substring(@date,1,4) = substring(current()/@date,1,4)]" mode="Month">
                <xsl:sort select="@date" data-type="text" order="ascending"/>
            </xsl:apply-templates>
        </div>
    </xsl:if>
</xsl:template>
 
<xsl:template match="Event" mode="Month">
    <xsl:if test="not(preceding-sibling::Event[substring(@date,1,7) = substring(current()/@date,1,7)])">
        <div>
            <xsl:call-template name="MonthName">
                <xsl:with-param name="MONTH" select="substring(@date,6,2)"/>
            </xsl:call-template>
        </div>
        <div class="indent">
            <xsl:apply-templates select="../Event[substring(@date,1,7) = substring(current()/@date,1,7)]" mode="Day">
                <xsl:sort select="@date" data-type="text" order="ascending"/>
            </xsl:apply-templates>
        </div>
    </xsl:if>
</xsl:template>
 
<xsl:template match="Event" mode="Day">
    <xsl:if test="not(preceding-sibling::Event[@date = current()/@date])">
        <div><xsl:value-of select="number(substring(@date,9,2))"/></div>
        <div class="indent">
            <xsl:apply-templates select="../Event[@date = current()/@date]" mode="Details">
                <xsl:sort select="@date" data-type="text" order="ascending"/>
            </xsl:apply-templates>
        </div>
    </xsl:if>
</xsl:template>
 
<xsl:template match="Event" mode="Details">
    <div><xsl:value-of select="concat(@description, ' (', @location, ')')"/></div>
</xsl:template>
 
<xsl:template name="MonthName">
    <xsl:param name="MONTH"/>
    <xsl:choose>
        <xsl:when test="$MONTH = '01'">January</xsl:when>
        <xsl:when test="$MONTH = '02'">February</xsl:when>
        <xsl:when test="$MONTH = '03'">March</xsl:when>
        <xsl:when test="$MONTH = '04'">April</xsl:when>
        <xsl:when test="$MONTH = '05'">May</xsl:when>
        <xsl:when test="$MONTH = '06'">June</xsl:when>
        <xsl:when test="$MONTH = '07'">July</xsl:when>
        <xsl:when test="$MONTH = '08'">August</xsl:when>
        <xsl:when test="$MONTH = '09'">September</xsl:when>
        <xsl:when test="$MONTH = '10'">October</xsl:when>
        <xsl:when test="$MONTH = '11'">November</xsl:when>
        <xsl:when test="$MONTH = '12'">December</xsl:when>
    </xsl:choose>
</xsl:template>
 
</xsl:stylesheet>
Listing 2. The Calendar.xsl file.
Bookmark this Article
StumbleUpon  Stumble It!
Digg  Digg It!
del.icio.us  del.icio.us
List of Figures
Listing 1 - The Events.xml file.
Listing 2 - The Calendar.xsl file.
Listing 3 - Filtering works correctly but does not account for date parts.
Listing 4 - Filtering fails because the substring() function prevents the preceding-sibling axis from working correctly.
Article Tags
Great Deals
TigerDirect Exclusive Deals, Limited Time Offers, Act Now And Save!
Find all current special offers on Adobe products.
Try SugarSync Free!
Join WebHost4Life.com
TigerDirect
Computers4SURE (4SURE.com - An Office Depot Co.)
Copyright © 2006-2010 Braintrove. All rights reserved. Braintrove, braintrove.com, and the Braintrove logo are trademarks of Gregory Scot Collins in the United States and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners. Any rights not expressly granted herein are reserved.