Dan Connolly's tinkering lab notebook

hacking soccer schedules into hCalendar and into my sidekick

When I gave a microformats+GRDDL talk early this month, I listed my kid's soccer schedules on my wish list slide.

Those soccer schedules are now available. No matter how badly I need them in my sidekick calendar in order to coordinate other family activities, I couldn't bear the thought of manually keying them in. The bane of my existence is doing things that I know the computer could do for me.1998,2002

One of the schedules is in PDF. I toyed with a PDF to excel converter and with google's "view as HTML" cache feature but didn't get very far with those. But the other schedule is on a normal database-backed web site.

It took just 91 lines of XSLT to put hCalendar markup to the page. Each event was a row; I added a tbody element around each row so that I could use the row element as the class="description" element. I used an ASP recipie to figure out how to just add an attribute here and there and leave the rest alone. I didn't get the AM/PM XSLT code right the first time; silly, since I've written it before; I should have copied it, if not factored it out for reuse.

My PDA/cellphone is a t-mobile sidekick. There's a very nice XMLRPC interface to the data, but it went read-only and it's not supported, so I use a ClientForm screen-scraping hack to upload flight schedules and such to my PDA. (in my palmagent project) gets its data thru a simple command-line interface or thru tab-separated text files. I had a set of eventlines.n3 rules for reducing RDF calendar data to tab-separated format, but its timezone support is quirky and it doesn't handle multi-line descriptions. So I bit the bullet and integrated cwm's RDF reader via the simple myStore API into I was simple enough:

elif o in ("--importRDF",):
import uripath, os
from myStore import load #
addr = uripath.join("file:" + os.getcwd() + "/", a)
kb = load(addr)
importTimedRDF(number, passwd, kb, icon


from myStore import Namespace
RDF = Namespace("")
ICAL = Namespace('')

for ev in kb.each(pred = RDF.type, obj = ICAL.Vevent):
titl = unicode(kb.the(subj = ev, pred = ICAL.summary)).encode("utf-8")
progress("== found event:", titl)

when = str(kb.the(subj = ev, pred = ICAL.dtstart))
dt = when[:10]
ti = when[11:16]

loc = kb.any(subj = ev, pred = ICAL.location)
if loc: loc = unicode(loc).encode("utf-8")
desc = kb.any(subj = ev, pred = ICAL.description)
if desc: desc = unicode(desc).encode("utf-8")

progress("a.addTimedEvent", dt, ti)
a.addTimedEvent(dt, ti,
titl, desc,
'minutes', 60, #@@hardcoded

So I succesfully loaded son's soccer schedule into my sidekick PDA calendar:

  1. GET the schedule
  2. tidy it
  3. add hCalendar markup (vevent, description, summary dtstart, location) using XSLT
  4. convert to RDF/XML using a GRDDL transform for hCalendar, glean-hcal.xsl
  5. load into sidekick using

The folks running the DB-backed web site could add hCalendar markup with even less hassle then I did (though they might have to think a little bit to produce well-formed XHTML), at which point I could reduce the first 4 steps with GRDDL (either via remote service or by adding GRDDL support to or to cwm's myStore.load() function).