Corey Mwamba

menu

Vendor-agnostic RDFa Event Markup

NOTE: this has been updated: I was using the rel in the wrong sense, and so I've removed that section.
Gregg Kellogg who helped make the Structured Data Linter also pointed out that Vcalendar is not a listed type for iCalendar in RDF - so I've removed references to that too, many thanks.

Introduction

Following on from my first experiment in marking up time-lines, I created a service that parses iCalendar data expressed as RDFa and produces an iCalendar file that you can either import or subscribe to. What follows is a description of how to produce the RDFa.

Why?

In writing up these notes, I was asked by getSchema to try its implementation in RDFa Lite and Microdata, which I had already done. What I needed from events mark-up - and what was not there in Schema.org - was

  1. the ability to have recurring events [although I notice that the RDFa in HTML working draft there is the potentially useful rdfa:copy attribute]
  2. a one-to-one [or as close as you can get] and extensible mapping of the current iCalendar standard, which is RFC 5545/6. Schema.org and microformats are still both based on a limited version of RFC 2445; and neither has a way of allowing non-standard properties.

These things are built from directly practical concerns - as a working musician I deal with dates all the time. Since I don't write the mark-up by hand but use PHP to generate the mark-up, it takes no more time to do this than using microformats, and frees up my class attributes for actual styling. It can get a bit more involved than marking up Schema.org, but for complex situations you're covered. The only thing I wasn't able to finish was how to do alarms - but it's on its way.

Single events

This is literally how simple this can be. I've highlighted the words I've marked up with RDFa:

There's a launch at Derby Museum and Art Gallery today, and I'll be doing a solo set for 1 hour until half-six.
Save to calendar

The event is contained within a paragraph, and the relevant words are marked-up to express the details of the event. To mark up events we have to use a common vocabulary of terms. The vocabulary needed is defined in an RDF file, at http://www.w3.org/2002/12/cal/ical#. Because all the terms we're going to use come from there, we can abbreviate that reference by creating an XML namespace for it called cal:

<p prefix="cal: http://www.w3.org/2002/12/cal/ical#">

We can now set the typeof of the paragraph as an event. The term for defining an event is at http://www.w3.org/2002/12/cal/ical#Vevent, but because we've set up a namespace we can now just write cal:Vevent.

<p prefix="cal: http://www.w3.org/2002/12/cal/ical#" typeof="cal:Vevent">

We want all of the information about the event to link to the event itself. We can do this by giving the paragraph an id; and then using the about property to point to the id. Yes, it's pointing to itself, but it makes sense to a computer.

<p prefix="cal: http://www.w3.org/2002/12/cal/ical#" typeof="cal:Vevent" id="gig" about="#gig">

We can then add each of our terms as a property. If we want the property to have a value in a specific format (e.g. dates and times must be expressed in ISO-8601) we can place them as a content attribute.

<p prefix="cal: http://www.w3.org/2002/12/cal/ical#" typeof="cal:Vevent" id="gig" about="#gig"> 
There's a launch at <span property="cal:location">Derby Museum and Art Gallery</span>
<span property="cal:dtstart" content="2012-11-02T17:30:00Z">today</span>,
and I'll be doing a <span property="cal:summary">solo set</span>
<span property="cal:duration" content="PT1H">for 1 hour</span>
until <span property="cal:dtend" content="2012-11-02T18:30:00Z">half-six</span>.
</p>

And that is pretty much it. If you copy the above code to the clipboard, you can extract the data and visualise it using rdfa.info.

Extra things

Say for example you were scheduling a meeting. Here's a plain, non-RDFa example:

I'm meeting Roger at The Book Cafe in the Cornmarket on Friday, at six.

Now I'll do as before, marking up the RDFa:

I'm meeting Roger at The Book Cafe in the Cornmarket on Friday, at six. Save to calendar

But then I need to consider - what if something changes, and this meeting is cancelled? I could simply delete it; but if I wanted to show that it had been cancelled, then we can use cal:status, and apply it as a property of the event. It can only take one of three values: CONFIRMED, CANCELLED, and TENTATIVE. You can then modify the presentation of the information on the page using CSS.

<p id="roger3" about="#roger3" typeof="cal:Vevent" property="cal:status" content="cancelled">
I'm meeting 
<span property="cal:summary">Roger</span> 
at 
<span property="cal:location">The Book Cafe in the Cornmarket</span> 
on 
<span property="cal:dtstart" content="2012-11-09T18:00:00Z">Friday, at six.</span></p>

I'm meeting Roger at The Book Cafe in the Cornmarket on Friday, at six. Save to calendar

Recurring events

Recurring events have other properties. So a recurring rule would be a resource that would have to relate itself to the event. Let's take the following statement:

I go running every day at five in the morning.

Save to calendar

We set rel=cal:rrule here and set its context through resource. I can then contain the mass of options within this.

<div typeof="cal:Vevent" prefix="cal: http://www.w3.org/2002/12/cal/ical#" id="run" about="#run">
<p>
<span>I go 
<span property="cal:summary">running</span> 
<span rel="cal:rrule" resource="#run"><span property="cal:freq" content="daily">every day</span></span>
<span property="cal:dtstart" content="2012-11-03T05:00:00Z">at five in the morning</span>.</span>
</p>

Recurrence can become quite complex to write - which is why you could get a machine/script to write it. But it can still be incorporated into natural language:

<p id="tut" about="#tut" typeof="cal:Vevent" prefix="cal: http://www.w3.org/2002/12/cal/ical#">
<span property="cal:summary">The tutorial</span> will be 
<span rel="cal:rrule" resource="#tut">
<span property="cal:interval" content="2">every other</span> <span property="cal:freq" content="weekly">week</span> <span property="cal:byday" content="mo,we,fr">on Mondays, Wednesdays, and Fridays</span> <span property="cal:until" content="2013-05-24T00:00:00Z">until 24 May, 2013</span>
</span>, <span property="cal:dtstart" content="2012-09-03T00:00:00Z">starting on 3rd September 2012</span>. </p>

The tutorial will be every other week on Mondays, Wednesdays, and Fridays until 24 May, 2013 , starting on 3rd September 2012.

Save to calendar

Attendees

listing attendees have a similar construction to recurring events, but the information is about the attendee, not the event. So we can set about to the URI of the attendee.


<ul rel="c:attendee">
<li property="c:role" content="req-participant" id="attendee1" about="http://www.example.com/joebloggs"><span property="c:cn">Joe Bloggs</span><span property="c:partstat" content="accepted" /></li>
<li property="c:role" content="req-participant" id="attendee2" about="http://www.example.com/SarahH"><span property="c:cn">Sarah</span><span property="c:partstat" content="accepted" /></li>
</ul>

Alarms

Here, I'll just show the pattern for constructing an alarm.

off to the doctors at 2 o'clock in a week or so.

<div prefix="a: http://www.w3.org/2002/12/cal/ical#" id="app1" about="#app1" typeof="a:Vevent">
<p><span property="a:summary">off to the doctors</span> <span property="a:dtstart" content="2014-06-14T14:00:00Z">at 2 o'clock in a week or so.</span></p> 
<p rel="a:Valarm" about="#app1" id="alarm" style="display: none">
<span about="#alarm">
<span property="a:action" content="display"></span>
<span property="a:trigger" content="+PT2H"></span>
<span property="a:duration" content="PT2M"></span>
<span property="a:repeat" content="1"></span>
<span property="a:description">Just a check up</span>
<span property="a:summary">Reminder</span>
</span>
</p>
</div>