Hack 49. Generate Geocoded RSS from Any Google Map
Don't tell anyone, but the Semantic Web really is cool.
One thing that bugs me about Google Maps is that, since the API is entirely JavaScript, the annotation layer in a hack is only available visually and is not machine parseable. It's understandable that Google didn't push any particular geodata file format, as these will emerge, but it's frustrating that right now so much cool data is being created as lone silos, in an inaccessible and un-remixable way.
Yet the data is there, in the JavaScript and Document Object Model objects created by the Google Maps API. It should be possible to muck around in there and rescue that data from its lonely and isolated existence. This hack describes a Firefox JavaScript Bookmarklet that pulls point annotation information from many Google Map hacks and produces geocoded RSS.
5.9.1. The Hack
The first step is to find the GMap object in memory, which is the key to the Google Maps object structure. Every page that shows a Google Map (under the official API) must have a line that looks like this:
var map = new GMap(document.getElementById("map"));
The bookmarklet assumes the GMap object is a global variable. If the page creates the GMap object within a function, the bookmark will fail. User-created global variables and methods can be accessed by iterating through the global object this. Without a JavaScript function to query an object for its user created class, the bookmarklet calls getCenterLatLng( ) on each global object within a TRy/catch block. If this call does not generate an error, the GMap object has been found and things can move forward. The other assumption is that overlays are GMarker objects that respond to click events by calling openInfoWindowHtml(). This is probably the most common way of constructing a Google Map.
Since there is no API method to list overlays, a JavaScript Data Dumper, such as the one at http://www.mattkruse.com/JavaScript/datadumper/, can be very useful to investigate the structure of the GMap object and find the overlays, without following through the API's obfuscated code. We can start by creating a basic Google Map with overlays and info windows, according to the documentation. Next, we load in datadumper.js, set DumperMaxDepth=2, and call DumperPopup(map). Setting DumperMaxDepth to a small value is crucial, since the GMaps object has self references and will send the Dumper into an infinite loop. The dump reveals an array within the GMap object called overlays. Calling DumperPopup(map["overlays"]) shows a list of objects, each containing a point property. Each GPoint object has an x and y value, which on inspection are the lat/long location of the overlay. Rockin'!
But what about the overlay content? That HTML exists within an anonymous function passed to the GEvent.addListener method. That function is placed in the _e_ _click array and is already compiled. The only way to get at that content is to call the function. The trick is to capture the call to openInfoWindowHtml by copying the existing method at GMarker.prototype.openInfoWindowHtml and replacing it with our own function, which captures the HTML argument when requested, and otherwise calls the original backed-up method.
Finally, the RSS is produced by iterating through the overlays array, grabbing the x and y from the point, executing call( ) on the _e_ _click function, and wrapping it up within an RSS item element. The geocoded RSS is then written to a new window.
5.9.2. The Code
The HTML below (and online at http://brainoff.com/gmaps/gmaps.bklet.html) produces a bookmarklet from this script, which can be copied to your Firefox toolbar. When viewing a Google Map, click the bookmarklet, and if the map has been produced according to the assumptions, RSS will be generated. It's not possible to change the content type of a document from JavaScript, so Firefox will render the RSS as HTML. View the source to see the XML.
Mikel Maron