How to dynamically serve a KML file with Ruby on Rails

Posted on August 24, 2007

Serving a KML file in Ruby on Rails is way easier than doing it in asp.net.

Here’s how I do it for my little display kml on a google map application.

First of all, you want to trick Google into thinking that the kml file is just a regular file with the extension “kml”. I do this by using a custom route in routes.rb that looks a little something like this:
map.connect ':controller/:action/:ignore_this_bit/:uuid.:format 
#The :ignore_this_bit is optional if you want to get around the google  
#caching issue detailed below
So that means you could serve the file with a url like this: http://www.my_domain.com/my_controller/get_kml/'random_number'/11.kml If you put a random number in there then you’ll get around Googles 4 minute cache. Next you create a controller method that will spit out the KML and render it to the browser using the send_data function like the example detailed below. (I load my kml data using a UUID by the way – but you can do it any way you want):
  def get_kml
    @kml_data = KmlData.find_by_uuid(params[:uuid])
    if @kml_data.kml     
        send_data @kml_data.kml
    else
      render :text => 'Kml is empty'
    end
  end

The @kml_data.kml variable contains the raw xml formatted kml.

The real guts of the function is the send_data function. This is rubys way of sending a file to the browser, which is how google expects to view the file.

And that’s it! Piece of cake!

How to dynamically serve a KML file in Asp.net 2.0

Posted on August 06, 2007

KML is the markup language that Google uses to represent markers in Google Earth – and NOW in Google Maps!

How it works, is that you store the KML in a file on a web server where Google can get at it. Google then goes at caches the file, and generates the output map markers.

But what if you want to display dynamic markers using KML?

Here’s how:

First add an aspx page to your project. This will be the page to serve the KML.

Create an xml document that will represent the kml file using the XmlDocument class. Should look something like this:
XmlDocument xmlDoc = new XmlDocument();

XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0","utf-8",null); 

// Create the root element
XmlElement rootNode  = xmlDoc.CreateElement("kml");
rootNode.SetAttribute("xmlns", @"http://earth.google.com/kml/2.1");
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement); 
xmlDoc.AppendChild(rootNode);
XmlElement documentNode = xmlDoc.CreateElement("Document");
rootNode.AppendChild(documentNode);

XmlElement iconNode = xmlDoc.CreateElement("Icon");
XmlElement iconHrefNode = xmlDoc.CreateElement("Href");
XmlText iconHrefText = xmlDoc.CreateTextNode("marker_image.gif");
iconHrefNode.AppendChild(iconHrefText);
iconNode.AppendChild(iconHrefNode);

documentNode.AppendChild(iconNode);

// MyMarkerClass is my own object used to hold my internal longlat stuff - replace with your own mechanism here
foreach (MyMarkerClass marker in markers)
{
  // Create a new <Placemark> element and add it to the root node
  XmlElement placeMarkNode = xmlDoc.CreateElement("Placemark");
  documentNode.AppendChild(placeMarkNode);

  // Create the required nodes
  XmlElement nameNode = xmlDoc.CreateElement("name");
  XmlText nameText = xmlDoc.CreateTextNode(marker.Name);
  placeMarkNode.AppendChild(nameNode);
  nameNode.AppendChild(nameText);
  XmlElement descNode = xmlDoc.CreateElement("description");                
  XmlText descriptionText = xmlDoc.CreateTextNode(marker.Description);                
  placeMarkNode.AppendChild(descNode);
  descNode.AppendChild(descriptionText);

  XmlElement pointNode = xmlDoc.CreateElement("Point");
  placeMarkNode.AppendChild(pointNode);

  XmlElement coordsNode = xmlDoc.CreateElement("coordinates");
  XmlText coordsText = xmlDoc.CreateTextNode(string.Format("{0},{1},{2}", marker.Long, marker.Lat, 0));
  pointNode.AppendChild(coordsNode);
  coordsNode.AppendChild(coordsText);                
}
Then, in your Page_Load method, write the KML directly to the output like this:
Response.ContentType = "application/x-msdownload";

XmlTextWriter writer = new XmlTextWriter(Response.OutputStream, null);
xmlDoc.WriteTo(writer);
writer.Flush();

Almost there! Now you’ll need to rewrite the url so that Google can try and find it with an innocuous “myfile.kml” path. We created a url rewriting method in house, but there are tutorials on line on how to do it (try here or here )

Now all you need to do is include the url rewritten kml path in your javascript, and Google will use it beautifully!

Auto zoom KML content on a google map

Posted on July 27, 2007

If you’ve seen my display KML on a google map page you’ll know that it doesn’t automatically zoom up on your generated markers. That’s cause I thought it was too hard and crazy to implement.

Turns out I was wrong.

If you’re populating a google map with data from a KML file, you can automatically centre and zoom to the right place just by adding this line of code:

geoXml.gotoDefaultViewport(map)

Where geoXml is your GGeoXml object and map is your GMap2 object.

How easy is that?!

Display your KML on a Google Map

Posted on July 12, 2007

KML – the Google Earth/Maps markup language – is a handy and convenient way of displaying geographical information on a google map.

To use it though you need to store your KML on a website somewhere where Google can get at it – which makes for quick and dirty KML experimentations a bit of a pain.

SO, I’ve created a quick little Rails application that let’s you see your KML straight away – without having to go through the rigmarole of saving it in a file somewhere first.

Check it out here: http://display-kml.appspot.com/

To use it, just type some KML into the box, click the button, then move around on the google map – pretty straight forward!

To get you going, here’s some interesting KML as provided by the Google Maps team. Paste this in then zoom up on Sicily!

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<GroundOverlay>
  <description>
     Overlay shows Mount Etna erupting on July 13th, 2001.
  </description>
  <name>Large-scale overlay on terrain</name>
  <LookAt>
    <longitude>15.02468937557116</longitude>
    <latitude>37.67395167941667</latitude>
    <range>30350.36838438907</range>
    <tilt>58.31228652890705</tilt>
    <heading>-16.5581842842829</heading>
  </LookAt>
  <visibility>0</visibility>
  <Icon>
    <href>http://bbs.keyhole.com/ubb/z0302a1700/etna.jpg</href>
  </Icon>
  <LatLonBox id="khLatLonBox751">
    <north>37.91904192681665</north>
    <south>37.46543388598137</south>
    <east>15.35832653742206</east>
    <west>14.60128369746704</west>
    <rotation>0</rotation>
  </LatLonBox>
</GroundOverlay>
</kml>

There’s some more cool KML samples here http://googlemapsapi.blogspot.com/2006/11/kml-on-google-maps.html