Calendar events and contact information with iCalendar and vCard
A common scenario in Enonic Vertical Site is listing events and contact information, and EVS provides a convenient interface for managing this across Intranets and public websites. Many users use desktop applications such as Microsoft Outlook to manage contacts and events, and may find it awkward to manually copy information from a website. In this article we will look at how we can use the iCalendar and vCard formats to enable users to automatically import information into their applications.
A brief overview of the formats
The iCalendar (based on the vCalendar format) and the vCard formats are for exchanging calendar events and contact information respectively, and supported by a large number of products. They are text based and fairly simple to work with.
Here is a sample iCalendar object that defines a project planning meeting on September 14th, from 09:00 to 10:30:
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//foo/bar//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:20081014T090000Z DTEND:20081014T103000Z SUMMARY:Project planning meeting END:VEVENT END:VCALENDAR
The field PRODID identifies the product (fictional in this case) that generated the data, and the date and times are in this case in UTC, as indicated by the Z at the end. To ensure that events appear at the right time in the calendar, a timezone should be specified. To specify a timezone other than UTC, DTSTART and DTEND should be on the following format:
DTSTART;TZID=Europe/Oslo:20081014T090000
Here is a sample vCard object that defines a contact:
BEGIN:VCARD VERSION:3.0 N:Doe;John;;; FN:John Doe EMAIL;type=INTERNET;type=WORK;type=pref:test@example.com TEL;type=WORK;type=pref:1234567 TEL;type=CELL:7654321 END:VCARD
This specifies a contact, John Doe, with an email address, work phone number and mobile phone number. The work phone number is in this case marked as preferred.
Content types for events and contacts
Before we show how to write XSLT for generating iCal and vCard objects, we will create two sample content types and create some content that we can use later. The first one we will call contact, the second event.
The first one will simply have first name, surname, email address and phone number:
<contenttype>
<config version="1.0">
<form>
<title name="surname"/>
<block name="Person">
<input name="firstname" required="true" type="text">
<display>First name</display>
>xpath>contentdata/firstname</xpath>
</input>
<input name="surname" required="true" type="text">
<display>Surname</display>
<xpath>contentdata/surname</xpath>
</input>
<input name="phone" type="text">
<display>Phone</display>
<xpath>contentdata/phone</xpath>
</input>
<input name="email" type="text">
<display>E-mail</display>
<xpath>contentdata/email</xpath>
</input>
</block>
</form>
</config>
<indexparameters>
<index xpath="data/surname"/>
<index xpath="data/firstname"/>
<index xpath="data/mobile"/>
<index xpath="data/email"/>
</indexparameters>
</contenttype>
The latter will have a title, description, start date, start time, end date and end time:
<contenttype>
<config version="1.0">
<form>
<title name="title"/>
<block name="Event">
<input name="title" required="true" type="text">
<display>Title</display>
<xpath>contentdata/title</xpath>
</input>
<input name="description" required="true" type="textarea">
<display>Description</display>
<xpath>contentdata/description</xpath>
</input>
</block>
<block group="contentdata/times" name="Start time">
<input name="starttime" type="text">
<display>Start time (hh:mm)</display>
<xpath>starttime</xpath>
<size value="5"/>
</input>
<input name="endtime" type="text">
<display>End time (hh:mm)</display>
<xpath>endtime</xpath>
<size value="5"/>
</input>
<input index="true" name="startdate" type="date">
<display>Start date</display>
<xpath>startdate</xpath>
<size value="10"/>
<maxlength value="10"/>
</input>
<input index="true" name="enddate" type="date">
<display>End date</display>
<xpath>enddate</xpath>
<size value="10"/>
<maxlength value="10"/>
</input>
</block>
</form>
</config>
<indexparameters>
</indexparameters>
</contenttype>
Next, create two categories, one for each content type, and add some events and contacts.
Generating vCard objects with XSLT
To generate iCal and vCard objects, we will be creating two page template XSLTs.
Generating vCards is fairly simple, our page template just needs to output the data as text on the form described earlier. Setting up XSLT to output text is not a problem, we just use xsl:output to tell the XSLT engine to output text. We will also set the correct media-type to make sure that the browser pass it on to the associated application.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet exclude-result-prefixes="saxon xs" version="2.0" xmlns:saxon="http://icl.com/saxon" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output encoding="utf-8" indent="no" method="text" omit-xml-declaration="yes" media-type="text/x-vcard"/> <xsl:template match="content"> <xsl:text>BEGIN:VCARD VERSION:3.0 N:</xsl:text><xsl:value-of select="contentdata/surname"/>;<xsl:value-of select="contentdata/firstname"/><xsl:text>;;; FN:</xsl:text><xsl:value-of select="contentdata/firstname"/><xsl:text> </xsl:text><xsl:value-of select="contentdata/surname"/><xsl:text> EMAIL;type=INTERNET;type=WORK;type=pref:</xsl:text><xsl:value-of select="contentdata/email"/><xsl:text> TEL;type=WORK;type=pref:</xsl:text><xsl:value-of select="contentdata/phone"/><xsl:text> END:VCARD </xsl:text> </xsl:template> </xsl:stylesheet>
The reason xsl:text is used so much here, is to ensure that we get the right formatting in the resulting text. In HTML, white space is not so important and we can accept spaces and newlines in places where they are not necessarily meant to be, but with both vCard and iCal, we need to pay special attention to this.
After creating this XSL, we can create a page template based on it, with the following datasource.
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<datasource>
<methodname>getContent</methodname>
<parameters>
<parameter name="key" override="url" type="int">-1</parameter>
<parameter name="parentLevel" type="int">0</parameter>
<parameter name="childrenLevel" type="int">2</parameter>
<parameter name="parentChildrenLevel" type="int">0</parameter>
<parameter name="updateStatistics" type="boolean">true</parameter>
<parameter name="relatedTitlesOnly" type="boolean">false</parameter>
<parameter name="userRights" type="boolean">false</parameter>
<parameter name="categoryFilter" type="int[]"/>
<parameter name="categoryRecursive" type="boolean"/>
<parameter name="ctyFilter" type="int[]"/>
</parameters>
</datasource>
</datasources>
Finally we create a page that we can link to with a content key to get our vCard generated.
Generating iCal objects with XSLT
Generating iCal objects can be a little bit more complex, it will depend on the type of event - perhaps recurring or multi-day event). In this case we will keep it simple and only generate events occurring on a single day.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet exclude-result-prefixes="saxon xs" version="2.0" xmlns:saxon="http://icl.com/saxon" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output encoding="utf-8" indent="no" method="text" omit-xml-declaration="yes" media-type="text/calendar"/> <xsl:template match="content"> <xsl:text>BEGIN:VCALENDAR VERSION:2.0 PRODID:-//enonic/vertical site//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:</xsl:text><xsl:value-of select="translate(contentdata/times/startdate, '-', '')"/>T<xsl:value-of select="translate(contentdata/times/starttime, ':', '')"/><xsl:text>00Z DTEND:</xsl:text><xsl:value-of select="translate(contentdata/times/enddate, '-', '')"/>T<xsl:value-of select="translate(contentdata/times/endtime, ':', '')"/><xsl:text>00Z SUMMARY:</xsl:text><xsl:value-of select="title"/><xsl:text> END:VEVENT END:VCALENDAR </xsl:text> </xsl:template> </xsl:stylesheet>
Next we create a page template and page, as we did for the vCard objects. It might also be necessary to give this page a name ending in ".ics", to make sure that the browser sends it to the right application, although it should be enough to set the media type (as we do in xsl:output).
Summary
As we have now shown, it is fairly simple to create vCard and iCal objects, and it has fairly high value for users who use calendar and address book applications. Although this article doesn't show all the intricacies of the formats, it should be a good starting point for extending websites with this kind of functionality.




Comments
If you want to comment on this article you need to be logged in.