Sunday, January 24, 2010

Parsing the Google Calendar XML Feed to Create New Calendars and RSS Feeds

We use Google's Calendar as part of our church web page. It's easy to keep up to date and we don't have to install any special calendar software on our server. It even has an extremely sophisticated XML feed. OK, the feed is considerably shorter, if you tweak the call a bit, using Google's published parameters. You can use this feed in an RSS aggregator, informing your readers about what's happening in the near future. But this might not be exactly what you want.

For instance: It's helpful to have a web-page listing of upcoming events, or a customized RSS feed.

This turns out to be relatively easy to do, if you know the trick, with a bit of PHP code. Let me say right off the top that I didn't come up with the PHP code myself, I got it from P.J. Cabrera, and it's available under what looks to be a pretty open license.

So I used Cabrera's script as the starting point to construct to scripts:

  • First, an HTML web page, google_calendar_xml_parse_to_html.html, with an embedded PHP script which calls a Google calendar XML feed and parses it to form a web page that looks something like this.
  • Second, a PHP script, google_calendar_xml_parse_to_rss.php, which parses the Google calendar XML feed to produce an RSS feed that looks like this.

The scripts are fully, possibly painfully, annotated, so you can see exactly what I did at every step. I'm not going to discuss them here, then, but you can add comments below, and I'll address them there.

Now you'd think I could just provide a link to each of the two annotated pages, and you'd get the annotated pages. This turns out not to be the case. The server will execute the PHP code on each page, and then ship XML. Don't believe me? Load up the web page and/or the RSS Feed and look at the source code. You won't find the PHP code, just perfectly formed XHTML or XML.

So I've put both scripts in this

tar file, parse_google_calendar.tar

(Sorry, my free web page server prohibits direct links to non-html pages, and doesn't allow ZIP files.)

Download the file, and you can extract both the html page, to create a calendar listing, and the php page, to create an RSS feed.

A few things to note:

  • Don't forget to change the web addresses, as indicated. You'll also need your Google Calendar address.
  • Note that the two files are linked, that is, the HTML page has a link to the PHP page, telling the world that the PHP is an RSS feed, and the PHP page links back to the HTML page, so that the reader can find your web site. You don't have to put in those links, of course.
  • Of course, this only works if your server can handle PHP, but that doesn't seem to be all that much of a problem.
  • Once the code is uploaded, you can check to be that the HTML page validates using the W3C validation service.
  • Similarly, you can see if the PHP script creates a valid XML page by using the W3C Feed validation service.

Put all comments below.

17 comments:

Daniel James Photography said...

many thanks for this, using it on my iphone friendly website to show photo shoot bookings :)

any idea what the delay time is between updating Google Calendar and it showing in the RSS? i.e. I updated an event with a new name and it hasn't shown yet?

thanks

Dan

rcjhawk said...

Good question. Google Calendar seems to remember its initial information. For example, I just moved a meeting from next week up to today. It shows up on the web page as the first item, but the date it shows is still next week.

Like many things, it's a mystery.

Maxime Guedj said...

Hi! Thanks very much but I don't manage to use your script...
Ok you can laugh at me but I don't understand how you can put some php in your html file.
Because when I visit the html page I got this:
Title

load( $feed ); // We're looking for all the entries in the feed, denoted, logically // enough, by the tag "entry" $entries = $doc->getElementsByTagName( "entry" ); // This is pretty much self-explanatory foreach ( $entries as $entry ) { // Find the status of a given entry $status = $entry->getElementsByTagName( "eventStatus" ); $eventStatus = $status->item(0)->getAttributeNode("value")->value; // If it's confirmed, parse it if ($eventStatus == $confirmed) { // This looks at the "title" tag. $titles = $entry->getElementsByTagName( "title" ); $title = $titles->item(0)->nodeValue; // $title might have an unescaped isolated ampersand in it (as in // "Chat & Chew".) This will fix that so that the web page will validate $title = ereg_replace(" & ", " & ", $title); // This looks at the "gd:when" tag, // to get the actual time the event is going to happen. // Note that the "gd" indicates this is part of the Google schema $times = $entry->getElementsByTagName( "when" ); // Pull off the time $startTime = $times->item(0)->getAttributeNode("startTime")->value; // Parse it into something we like. For other formatting options see // http://php.net/manual/en/function.date.php $when = date( "l\, F j\, Y \a\\t h:i A T", strtotime( $startTime ) ); // Ditto for location $places = $entry->getElementsByTagName( "where" ); $where = $places->item(0)->getAttributeNode("valueString")->value; // There may be multiple link elements in the file. This picks off // the first one, which takes you to the event page for the Google // calendar. Note that "link", like "title", is not part of the // Google schema, so it's referenced by "" rather than // "" $web = $entry->getElementsByTagName( "link" ); $link = $web->item(0)->getAttributeNode("href")->value; // You can pick off other tags, of course, but these are the ones // I need. // Now print out the HTML for this element. Be careful to // escape all of the double quotation marks. Note that // you don't really need the "\n" end of line characters, // I just put them in to make the resulting page easier to read // for debugging purposes echo "
\n"; echo "What: "; echo ""; echo "$title
\n"; echo "When: $when
\n"; echo "Where: $where\n"; echo "
\n\n"; } } ?>

So i'm quiet lost, could be great if you could help..

rcjhawk said...

Maxime,

Ah yes, this is probably something I should have written in the instructions.

PHP programs are run only as part of a web service, e.g., Apache. So if you don't have Apache running on your local machine, and you open the index page, you'll see the gobbledygook in your post.

Many developers install Apache on local machines, even if they aren't connected to the network, for testing scripts such as this. I've had no inclination to do so.


HOWEVER: Your web hosting service should run PHP programs as a matter of course. If they don't, then it's time to get a new service, even if your current one is free. If you edit the HTML file to fit your needs, upload it to your website, and go to

http://yourdomain.com/calendarfile.html

you should see the calendar listing in all it's glory.

OK, this assumes your browser is working correctly. If you click on http://www.unitedparishbowie.org/upcoming/ you do see a well-formed web page, don't you?

Joblio said...

Mr. Hawk - thanks for this tutorial and script! I was successfully able to implement both the to-rss and to-html scripts on Wordpress for my family's coffee shop website. It was a great introduction to this.
-Joblio

Maxime Guedj said...

Thanks for your answer. It wasn't the problem but still I've found now that I google calendar embedding works pretty well even on a mobile site so I used it instead.

Gainesville Computer Repair said...
This comment has been removed by the author.
Gainesville Computer Repair said...

Had a small snag but was able to figure it out. Excellent script, thank you for sharing!

Thiago C. said...

Very useful script, thank you for sharing! :)

Distant_Thunder said...

I hope this comment thread is not completely dead yet, but I was having the same issue with php not loading as Maxime Guedj, and I DID have apache2 installed. I mean when I type http://localhost, it does work. I can also see the 'upcoming events' on my browser just fine.

Can someone help me figure this out?

Anonymous said...

Yes, I was having the same problems as Distant Thunder as well - wondering if there was a solution:???

Mike D said...

Is there a guide somewhere about grabbing other fields beside the title, time and locations? Such as a paragraph with the description and maybe display a small photo relating to the event. Thank you! I have been looking around online but nothing seems similar to this example

Sarea said...

I am having the exact same issue as Maxime, I see the same code instead of the feed using both Firefox and Internet Explorer when the pages are loaded from a PHP-enabled server, as well as on the example link provided. I shared the link to both pages with someone and they also see the same thing. Any suggestions would be hugely appreciated.

rcjhawk said...

Sarea,

I'm embarrassed. Not many people look at that page, and I hadn't checked it out for a while.

We recently had some problems with the server at our ISP, where our home page wasn't being displayed, but downloaded. As a result, we changed some of the PHP settings. Obviously we didn't check what happened to page.

Mind you I'm not blaming our ISP, who handled our problem promptly. The didn't know that the PHP listing page was there, and I forgot about it. So it's my fault.

But it's going to require some debugging, as the obvious fix didn't do it. It may take a couple of days for me to have time to talk to the ISP about the situation. When (if?) we find the solution I'll post a note here.

Sorry for the difficulties.

rcjhawk said...

Should also say that I don't have Apache set up locally, everything is on the ISP, so I have to test PHP scripts live, as it were. One of these days I'll have time to fix that, too.

Sarea said...

rcjhawk, I found the issue with my code, I was still loading it from a html page instead of a php. Changing the file extention resolved the issue. Thank you for all your help.

echi said...

Hello, I am not certain if you still look at comments for this script but it was of great help to me. I am trying to add another entry from an event but I don't know how to do it. I am trying to access the "Event Description" part of the entry (in the content tag). Could you point me in the right direction?
Thanks