Thursday while I was listening to Ben Hammersly's talk on the semantic something or other, I noticed that he had a box on his weblog that showed events he was planning to attend in the near future. I thought that was a good idea, so I put one on my weblog too. If you look to the right, you'll see a box labeled Upcoming Events that lists things I'm planning on going to in the next 90 days. I didn't really want to double enter this on my calendar and my blog, so I decided I'd link the box on my blog to the calendar I keep on my Powerbook. This is the story of how I did it.
You're probably aware, if you use iCal, that it stores its calendars in iCalendar format. What's more, it can display and create multiple calendars in a color coded way so that events can be conveniently categorized. My plan was pretty simple. I'd create a special calendar called Travel and put my travel related entries there. That would put them all in a single file called Travel.ics in iCalendar format. Then I'd parse the file and turn it into HTML. That would give me something to suck into my blog.
It turns out that there aren't any complete libraries for parsing iCalendar files in Perl, but there is a PHP application called PHP iCalendar that has a nice iCalendar parser. The application is designed to display iCalendar formatted calendars on a web site. One of the nice features is an RSS generator for calendars. Now, I've never written any PHP before, but I've written tens of thousands of lines of Perl, so I figured I'd be OK. Besides, it easier to learn a new langauge than to write a parser. :-)
My standard procedure for learning a new language is to just jump right in and start modifying some existing code to do what I want. The RSS code looked the closest, so I copied it to a file called events.php and got started. It turns out that it wasn't very close--by the time I was done, there wasn't much of the original file left. I wanted to display only the all day events for the next 90 days. I put things like airline departure times and hotel check-in info in my calendar as well and I didn't want those on my blog. I also wanted to link the event title to a blog entry describing it when one existed. The latter is not directly supported by iCal, so I store the link as a tagged entry in the Notes field like so:
The code accesses each of the all day events in the parsed calendar during the next ninety days in order. The parsed calendar breaks repeating events apart, so I had to collect them back together. Luckily, they're all on sequential days or it would be harder. The code also greps for any link: tags in the DESCRIPTION field (what the Notes become in the iCalendar file) and pulls the URL out. Finally it spits them all out in the HTML of my choice.
The PHP module is available on my local web server and I use a cron job (check out Cronnix for a nice GUI crontab tool) to copy the files over to where the PHP program can access it. The results are available for the price of a GET. This chunk of code pulls the resulting HTML into my Radio template
<% local(s_str=string.urlEncode("XML")); local(url="http://panther.local/phpicalendar/rss/events.php?cal=Travel"); local(s= tcp.httpReadUrl(url)); return(s) %>
A few notes on the implementation:
- A more general events module would grab all-day events as an option, not just the only way its done. I should also handle repeating events in a more general way. My code, for example, will make a hash of overlapping repeating events. Luckily, I don't plan to travel to more than one place at a time.
- The file should probably spit out RSS or some other XML variant and then use an XSLT service to turn it into HTML so that its useful for more than just feeding my blog.
- This is my first PHP code, so if you promise not to make fun of me, I'll share it with you. If you make any improvements, please let me know.
- I wish the iCalendar format was an XML-based standard. That would have made this job easier.
XML or not, this is a great example of how having data freely available in a standard format frees it from the tyranny of the application.