This is the seventh in a series of entries about the SPARQL calendar demo. If you haven't already, you can read the previous entry.
After one or more people have been discovered, the calendar demo allows us to select one or more people and click the refresh link in the Calendars section of the righthand panel in order to retrieve calendar events for the selected person(s). Clicking refresh with the Alice demo user selected runs this SPARQL query:
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX ical: <http://www.w3.org/2002/12/cal/icaltzd#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT DISTINCT ?title ?start ?end ?name ?location ?g WHERE { { { <http://thefigtrees.net/lee/sw/demos/calendar/data/alice#alice> rdfs:seeAlso ?g . ?g rdf:type ical:Vcalendar . OPTIONAL { <http://thefigtrees.net/lee/sw/demos/calendar/data/alice#alice> foaf:name ?name } . OPTIONAL { <http://thefigtrees.net/lee/sw/demos/calendar/data/alice#alice> rdfs:label ?name } . } } . GRAPH ?g_wrapped { _:ev ical:summary ?title ; ical:dtstart ?start ; ical:dtend ?end ; ical:location ?location . FILTER (regex(str(?start), '2006-04.*') || regex(str(?end), '2006-04.*')). }. FILTER regex(str(?g_wrapped), str(?g)) . }
In English—and amidst some devilish hackery—this query says:
Fetch Alice's name. Also, for every event in the graph containing her calendar entries, fetch the event's title, start time, end time, and location.
At a first glance, we see that this query finds a person's calendar events using the same breadcrumbs protocol we've discussed previously. But as with the other SPARQL queries we've looked at so far, there are several other points worthy of note and discussion in this query:
- How does this query deal with multiple people? With this query, we are retrieving individual people's calendar events. Because one person's calendar, in this context, is independent of another's, we can fetch multiple people's calendars simultaneously by using the SPARQL UNION keyword to retrieve different rows (events) for different people.
- Why does this query retrieve the name of the person, when we've already seen a query that retrieves names? Much of what is done in the SPARQL calendar demo could be enhanced by saving client-side state. When Elias and I developed the demo, we made a point of avoiding state as often as we could, in favor of using SPARQL queries to do as much heavy-lifting as possible. Since we wish to display a person's name alongside their calendar in the righthand panel, we retrieve that information along with the calendar events in this query.
- What's the purpose of the filter expressions on ?start and ?end? There's no need to retrieve any calendar events which we can't render on the current calendar control on the main part of the webpage. To limit the events returned, we require that either the start date or the end date of each event match a regular expression which specifies the current month shown on the main calendar. (We know that the dates will conform to this format given that the RDF Calendar note specifies that the range of these properties is the XML Schema dateTime type.) This filter expression uses the SPARQL regex filter function to perform the matching.
- What's the difference between ?g and ?g_wrapped? How are they related? Very little published calendar data on the web is represented in RDF; much is published in iCalendar format. Thanks to DanC's python wizardry and Elias's hosting, though, we have resolvable URLs that resolve to iCalendar data represented as RDF. So, we can include a URL like http://torrez.us/services/ics2rdf/?ical=http://example/myCalendar.ics as a named graph in the RDF dataset of our query, and then match events within that calendar by sticking a pattern inside the SPARQL GRAPH keyword. But, it's unrealistic and semantically incorrect for someone to publish these triples
<http://example/me> a foaf:Person . <http://example/me> rdfs:seeAlso <http://torrez.us/services/ics2rdf/?ical=http://example/myCalendar.ics> . <http://torrez.us/services/ics2rdf/?ical=http://example/myCalendar.ics> rdf:type ical:Vcalendar .
rather than<http://example/me> a foaf:Person . <http://example/me> rdfs:seeAlso <http://example/myCalendar.ics> . <http://example/myCalendar.ics> rdf:type ical:Vcalendar .
If in our query, then, we used the same variable for both the object of rdfs:seeAlso and also for the graph name in the GRAPH clause, we wouldn't get back any rows, because the former's value is <http://example/myCalendar.ics> while the latter's value is <http://torrez.us/services/ics2rdf/?ical=http://example/myCalendar.ics>. So rather than sharing a variable, we use two different variables and use the built-in regex function as a poor man's (and unreliable) String.subStringOf substitute.
This is an ugly hack. Anyone reading this should be outraged. I was, but sometimes deadlines beckon. This is an ugly hack not least of all because the all of those ics2rdf URLs are invalid URL syntax (the reserved characters in the ical query parameter should be URL escaped). A possible solution would be to extend our calendar convention to require that a person's FOAF data contain a triple along the lines of: <http://example/myCalendar.ics> ex:asRDF <http://torrez.us/services/ics2rdf/?ical=http%3A//example/myCalendar.ics>. That's ugly, also, but perhaps a bit better. When we look at the queries that deal with people's interests and make use of data from upcoming.org, we'll see that this is a more general problem: when we access non-RDF data as RDF, how do we semantically associate the (different) URLs of (different) representations of the same data in a manner which is relatable within a SPARQL query? Elias wrote about this dilemma and solicited opinions ranging from handling this at an application level (but how do we do that with the current SPARQL Protocol over the web?) to extending the expressibility of SPARQL FROM NAMED clauses.
It's not always pretty when one takes a peak behind the curtain. As I've said before, these aren't new issues, but as far as I can tell they're sitll unsolved issues, and as such deserve whatever attention we can give to them.