Wednesday, August 25, 2010

Using a Google Map as a database – Part 1

In a nutshell: Create a Google Map to save placemarks that contain other (than geodata) types of business information, like name, URL, description, that can be read using the Google Maps Data API in the form of an ATOM feed, that can be easily parsed using the new WCF REST Starter Kit and integrated into your website.

I had a need recently to create a small dataset (around 50 items, and not expected to grow much beyond that) to form the basis for a new Accommodation section of my website. The dataset would consist of a list of accommodation providers, each item having properties like name, URL, type, etc. Since these were actual hotels and guesthouses, etc, I also wanted to store the location of each provider. Up to that point I had stored the list as individual bookmarks in Delicious, and populated my links page by requesting the Delicious feed of my bookmarks, filtering by the tag "accommodation". But Delicious doesn't allow you to associate geodata with bookmarks. Nowadays, any page showing a list whose items have a physical location meaningful within the app should show a map of those items, no question.

Organising (this corner of) the world's data
So, I decided to move the data to a Google Map, and wondered about where within the map I could squeeze the non-geographical information for each hotel, etc. When creating a map by hand, as opposed to programmatically as the new Maps Data API allows, the only place to save anything relating to a placemark is in the info-window for that placemark. One of the reasons for using a Google Map to store data like this is to benefit from the searchability and indexing of your map data - this is Google property, after all. So, unless you turn your back on the web and make the map private, the map has to work and make sense as a browseable object, independent of any data-storage purpose to which you might co-opt it. You want to have that info-window show something that looks ok.
Google Map

I decided to use a simple pseudo-HTML schema to store each hotel's information. An image, a link, and some social media links would do, and would result in a good-looking info-window, as well as storing all the information I needed. It's a combination of first-class data (URL: http://www.dolphinbeachhouse.com, Name: Dolphin Beach House, Location: Clifden, etc), presentation markup to make the info-window look ok (img align="absmiddle"...), and repetitive absolute references to the base URL of my site that I'd rather not have to set over and over, but which are necessary here.
<img src="http://www.connemara.net/Accommodation/images/providers/Dolphin.jpg">
<div>
    <a href="http://www.dolphinbeachhouse.com">Dolphin Beach House</a>
</div>
<div>
    <span type="type">Guesthouse</span>, <span type="location">Clifden, Sky Road</span>
</div>
<div>
    <span type="facebook">
    <img align="absmiddle"src="http://www.connemara.net/images/facebook.jpg">&nbsp;
<a href="http://www.facebook.com/DolphinBeachHouse">Facebook</a>
    </span>
</div>
If you try and make this XHTML-compliant, by the way, you won't be able to, or at least you'd probably end up in a semantic mess. Place a closing "/>", for instance, on the initial img tag, and watch it disappear when you save. Using span tags and type attributes to convey meaning, I had something that looked ok in the placemark's info-window, and a simple storage schema.

The Feed
Having created a map, and entered some placemarks, you can then get a feed of that map with the RSS link supplied by Google Maps. Parsing that feed gives you your data. So why bother using the Maps Data API? Well, here is how the RSS feed gives you that info-window HTML store:
<title>Dolphin Beach House</title>
<description><![CDATA[
<img src="http://www.connemara.net/Accommodation/images/providers/Dolphin.jpg">
<div>
    <a href="http://www.dolphinbeachhouse.com">Dolphin Beach House</a>
</div>
<div>
    <span type="type">Guesthouse</span>, <span type="location">Clifden, Sky Road</span>
</div>
<div>
    <span type="facebook"><img align="absmiddle" src="http://www.connemara.net/images/facebook.jpg">&nbsp;
<a href="http://www.facebook.com/DolphinBeachHouse">Facebook</a>
</div>]]>
</description>
...
<georss:point>53.497799 -10.094558</georss:point>
<georss:elev>0.000000</georss:elev>
but when you use the Data API feed, you get an ATOM feed, and within each entry: proper KML business (which will become important later on):
<content type="application/vnd.google-earth.kml+xml">
<Placemark xmlns="http://www.opengis.net/kml/2.2">
<name>Dolphin Beach House</name>
<description><![CDATA[
<img src="http://www.connemara.net/Accommodation/images/providers/Dolphin.jpg">
<div>
    <a href="http://www.dolphinbeachhouse.com">Dolphin Beach House</a>
</div>
<div>
    <span type="type">Guesthouse</span>, <span type="location">Clifden, Sky Road</span>
</div>
<div>
    <img src="http://www.connemara.net/Accommodation/images/facebook.jpg" align="absmiddle">&nbsp;
<a href="http://www.facebook.com/DolphinBeachHouse">Facebook</a>
</div>]]>
</description>
<Style>
<IconStyle>
<Icon>
<href>http://maps.gstatic.com/.../blue-dot.png</href>
</Icon>
</IconStyle>
</Style>
<Point>
<coordinates>-10.094558,53.497798,0.0</coordinates>
</Point>
</Placemark>
</content>
Sitting within the content tags - that there's a KML snippet, and that's important. All you'd have to do is wrap it in a
<?xml version="1.0" encoding="UTF-8" ?>
<kml xmlns="http://www.opengis.net/kml/2.2">
and a
</kml>
and you'd have a Google Earth file.

KML is a standard - it transcends the Google universe - and so you have one important standard, KML, delivered via another - ATOM. Standards are important: old farts who play jazz instinctively know this. If we could just get 'Summertime' in there, we'd have 3.

The Data API feed is in ATOM format, as I mentioned, and ATOM is fast-becoming a well-supported means by which collections (such as a map's placemarks) can be returned from a service to a web application for processing, as well as being of course an alternative to RSS for syndicating content on the web.

So, how do you read an ATOM feed containing your placemarks' datastore into your web application? Well, one way would be to use WCF with REST. More in part 2.