I noticed that Google Earth ships with something called GPSBabel (and my old friend expat.dll). Now I knew almost nothing about the world of GPS devices but I soon found that there are (too) many GPS file formats in the world. GPX seems to have become the de-facto XML standard but because of the wide variety of GPS hardware there are still plenty of different plain text file formats kicking about. GPSBabel is GPS format conversion software. I noticed that Google Earth can load GPX files! I found that using free GPS conversion utilities like GPS utility, G7toWin and GPSBabel I can pretty much convert anything I find on the net into a format that I can import in Google Earth (the freeware version!).
Secondly, I thought I could write an XSL to convert GPX to KML and vice versa but I found to my delight that GPSBabel has provisional support for converting GPX to KML, so I can leave the XSL stylesheet to someone who really needs to do it.
All this is good so far but what if I want to put the route of a walk on my website using Google Maps API. How difficult is it to convert KML (or GPX for that matter) into the Google Maps API. I wrote two stylesheets that generate the Google Maps JavaScript that make a map containing a "GPolyline" of a route. I used a GPS text file of walk around the Lake District in Cumbria (in England). Surprisingly it is *much* easier to transform GPX to Google Maps than the KML format. My conclusion would be if you're veering towards using Google Earth professionally then don't throw away your GPX files until someone writes an XSL to convert them back from KML format (you need an escape strategy).
Get your Google Maps API key here.
KML to Google Maps API XSL Stylesheet.GPX to Google Maps API XSL Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "text" version="1.0" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:apply-templates select="*[local-name()='kml']/*[local-name()='Document']"/>
</xsl:template>
<xsl:template match="*[local-name()='kml']/*[local-name()='Document']">
<xsl:apply-templates select="*[local-name()='Folder']"/>
</xsl:template>
<xsl:template match="*[local-name()='Folder']">
<xsl:apply-templates select="*[local-name()='Folder' or local-name()='Placemark']"/>
</xsl:template>
<xsl:template match="*[local-name()='Placemark']">
<xsl:apply-templates select="*[local-name()='MultiGeometry']"/>
</xsl:template>
<xsl:template match="*[local-name()='MultiGeometry']">
<xsl:apply-templates select="*[local-name()='LineString']"/>
</xsl:template>
<xsl:template match="*[local-name()='LineString']">
<xsl:apply-templates select="*[local-name()='coordinates']"/>
</xsl:template>
<xsl:template match="*[local-name()='coordinates']"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps API Example - overlay</title>
<style type="text/css">
v\:* {
behavior:url(#default#VML);
}
</style>
<script src="http://maps.google.com/maps?file=api&v=1&key=ABQIAAAA4Wxrd1ZmQfRHvggZWM0QkxSywvohUEBj468j1bHLctjAi9H1aRTgpH5EJsqp8F3DqOP3spOw36wc2A" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
function onLoad() {
var map = new GMap(document.getElementById("map"));
map.setMapType(G_HYBRID_TYPE)
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
<xsl:call-template name="firstPoint">
<xsl:with-param name="str" select="normalize-space(.)"/>
</xsl:call-template>
var points = [];
<xsl:call-template name="split">
<xsl:with-param name="str" select="normalize-space(.)"/>
</xsl:call-template>
map.addOverlay(new GPolyline(points));
}
//]]>
</script>
</head>
<body onload="onLoad()">
<div id="map" style="width: 500px; height: 300px"></div>
<div id="message"></div>
</body>
</html>
</xsl:template>
<xsl:template name="firstPoint"><xsl:param name="str"/>
<xsl:if test="contains($str,' ')"> map.centerAndZoom(new GPoint(<xsl:value-of select="substring-before(substring-before($str,' '),',0')"/>), 5);
</xsl:if>
</xsl:template>
<xsl:template name="split"><xsl:param name="str"/>
<xsl:choose><xsl:when test="contains($str,' ')"> points.push(new GPoint(<xsl:value-of select="substring-before(substring-before($str,' '),',0')"/>));
<xsl:call-template name="split">
<xsl:with-param name="str" select="normalize-space(substring-after($str,' '))"/>
</xsl:call-template></xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "text" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="*[local-name()='gpx']"/>
</xsl:template>
<xsl:template match="*[local-name()='gpx']"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps API Example - overlay</title>
<style type="text/css">
v\:* {
behavior:url(#default#VML);
}
</style>
<script src="http://maps.google.com/maps?file=api&v=1&key=ABQIAAAA4Wxrd1ZmQfRHvggZWM0QkxSywvohUEBj468j1bHLctjAi9H1aRTgpH5EJsqp8F3DqOP3spOw36wc2A" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
function onLoad() {
var map = new GMap(document.getElementById("map"));
map.setMapType(G_HYBRID_TYPE)
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
var points = [];
<xsl:apply-templates select="*[local-name()='trk']/*[local-name()='trkseg']/*[local-name()='trkpt']"/>
map.addOverlay(new GPolyline(points));
}
//]]>
</script>
</head>
<body onload="onLoad()">
<div id="map" style="width: 500px; height: 300px"></div>
<div id="message"></div>
</body>
</html>
</xsl:template>
<xsl:template match="*[local-name()='trk']/*[local-name()='trkseg']/*[local-name()='trkpt']">
<xsl:if test="position() = 1">
map.centerAndZoom(new GPoint(<xsl:value-of select="@lon"/>, <xsl:value-of select="@lat"/> ), 5);
</xsl:if>
points.push(new GPoint(<xsl:value-of select="@lon"/>, <xsl:value-of select="@lat"/> ));
</xsl:template>
</xsl:stylesheet>
Google Earth
Google Maps
Also a few other miscellaneous things I've noticed recently about Google Earth and it's sister Google Maps.
- The user-agent for Google Earth is kh_unk/unk
- Google Maps core functionality isn't really that AJAXy, all the co-ordinates for the map tile URLs are calculated in the client side JavaScript (granted, it is still extremely clever)
- Both Google Earth and Google Maps use the same server for the keyhole satellite maps: kh.google.com
- Google Maps also uses a server called: mt.google.com, I'm guessing the "mt" stands for map tiles
- Both mt and kh servers run Linux! Hurray!
- The "web server" on kh is running Keyhole Server 2.4
- The "web server" on mt is running something called "tfe" - (educated guess, does the "t" stand for telemetry?)
- There is a Google Earth server hardware available for industry but no mention anywhere of how much it will cost, I suspect if you have to ask you can't afford it!