Roman Nurik, Google Geo APIs Team
January 2009
KML is a file format used to display geographic data in an Earth browser such as Google Earth, Google Maps, and Google Maps for Mobile. It was originally designed by Keyhole, Inc. (acquired by Google) and is currently maintained by the Open Geospatial Consortium, Inc. (OGC). You can find a significant amount of documentation for KML on Google Code and a large assortment of community-contributed KML datasets can be found in the Google Earth Gallery.
KML plays an important role in all of the Google Geo developer products,
especially the Google Earth API. This article describes how to load and display
KML files in the Google Earth Plug-in using fetchKml (or Network
Links) as well as how to do the same with arbitrary KML strings using
parseKml.
This article assumes you are familiar with JavaScript and know the basics of the Earth API. Make sure you have read the Developer's Guide and have tried the Hello, Earth Demo before you continue.
| KmlNetworkLink | fetchKml | parseKml | |
|---|---|---|---|
| Coding difficulty | Easy | Medium | Easy |
| Allows for manipulating KML before displaying it | No | Yes | Yes |
| KML source | URL pointing to a KML or KMZ file | URL pointing to a KML or KMZ file | KML String |
| Data return method | N/A (no KML data is returned) | Asynchronous (data returned via a callback function) | Synchronous (data returned immediately) |
In summary, if you need a quick and easy way of showing a hosted KML file and you do not need to do any intermediate processing, use the KmlNetworkLink approach. If you do need to do intermediate processing (for example, if you need to run through the features in the KML file and do something with them), use the fetchKml technique. Finally, if you have a string containing KML (as opposed to a URL), use the parseKml method.
The following is a garden variety Hello, Earth sample:
<html>
<head>
<script src="http://www.google.com/jsapi?key=YOURAPIKEY"></script>
<script>
google.load('earth', '1');
var ge = null;
function init() {
google.earth.createInstance('map3d', initCallback, failureCallback);
}
function initCallback(pluginInstance) {
ge = pluginInstance;
ge.getWindow().setVisibility(true);
}
function failureCallback() {
// we can do something here if there's an error
}
</script>
</head>
<body onload="init()" id="body">
<div id="map3d" style="width: 500px; height: 500px;"></div>
</body>
</html>
Suppose that as soon the ge plugin instance is finished
loading, you want to display a KML file that is hosted at some public URL. To do
this, create a KmlNetworkLink that points to this URL.
First, look at the following sample <NetworkLink> snippet
that displays a KML file in the Google Earth client:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<NetworkLink>
<flyToView>1</flyToView>
<Link>
<href>http://path/to/your.kml</href>
</Link>
</NetworkLink>
</kml>
Since the Earth API is designed to mimic KML, it's fairly straightforward to
map this KML snippet to the Earth API to display a KML file in the Google Earth
Plug-in. Modify the initCallback code and add a simple new method
as in the following code example:
function initCallback(pluginInstance) {
ge = pluginInstance;
ge.getWindow().setVisibility(true);
// Earth is ready, we can add features to it
addKmlFromUrl('http://path/to/your.kml');
}
function addKmlFromUrl(kmlUrl) {
var link = ge.createLink('');
link.setHref(kmlUrl);
var networkLink = ge.createNetworkLink('');
networkLink.setLink(link);
networkLink.setFlyToView(true);
ge.getFeatures().appendChild(networkLink);
}
If you've worked with JavaScript and the HTML DOM before, you should feel
right at home. Just as you can use document.createElement('IMG') to
create an <img> tag in JavaScript, you can use
ge.createNetworkLink (example) to create
<NetworkLink> elements.
One of the drawbacks to this approach is that you can't modify the loaded
KML file before you display it. If you need to do that, you can use
fetchKml, as described below.
Suppose that you want to do some intermediate processing before displaying a
KML file in the Google Earth Plug-in. To do this, we will use
fetchKml, which takes a URL string and returns an object derived
from the KmlFeature
class, representing the DOM
hierarchy representing the contents of the URL.
Modify the addKmlFromUrl function as in the following
example:
function addKmlFromUrl(kmlUrl) {
google.earth.fetchKml(ge, kmlUrl, kmlFinishedLoading);
}
Then, write the code for the kmlFinishedLoading callback
function, which adds kmlObject to the Google Earth Plug-in
instance's own DOM hierarchy:
function kmlFinishedLoading(kmlObject) {
if (kmlObject) {
ge.getFeatures().appendChild(kmlObject);
}
}
One of the key benefits to this method is that you can now traverse the loaded
kmlObject and modify its DOM as needed before calling
appendChild to show it to the end user. For example, if you want
to remove the first child feature in the DOM tree, modify the
kmlFinishedLoading function like so:
function kmlFinishedLoading(kmlObject) {
if (kmlObject) {
// check if the object is a KmlContainer (folder or document)
if ('getFeatures' in kmlObject) {
var firstChild = kmlObject.getFeatures().getFirstChild();
if (firstChild !== null) {
kmlObject.getFeatures().removeChild(firstChild);
}
}
ge.getFeatures().appendChild(kmlObject);
}
}
For more information on DOM traversal, see the API references for KmlContainer::getFeatures() and GESchemaObjectContainer.
A caveat with the fetchKml method is that the plugin view isn't
automatically adjusted to zoom in on the KML file that was added. Currently, the
best and most portable way of doing that is by supplying a document-level
<LookAt> in your target KML file:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<LookAt>
...
</LookAt>
...
</Document>
</kml>
and then manually flying to that view like so:
function kmlFinishedLoading(kmlObject) {
if (kmlObject) {
ge.getFeatures().appendChild(kmlObject);
if (kmlObject.getAbstractView() !== null)
ge.getView().setAbstractView(kmlObject.getAbstractView());
}
}
The target KML can have any type of Feature as the root
element, be it <Document>, <Folder>,
<Placemark>, etc. The kmlObject variable will be
an instance of the corresponding Kml... class, such as KmlDocument,
KmlFolder,
KmlPlacemark,
etc.
Under the hood, fetchKml and the Google Earth Plug-in do the following:
fetchKml tells the Google Earth Plug-in to initiate an
asynchronous HTTP GET request to the provided URL.
Note: fetchKml returns immediately with no return value, since results are retrieved asynchronously.
fetchKml then calls the provided JavaScript callback function
with a KmlFeature
instance representing the DOM as the first argument.If at any point there is an error (HTTP error or KML parsing error),
fetchKml will call the callback function with a null
first argument.
Sometimes it is desirable to display an arbitrary KML string that isn't
hosted publicly. For these cases, the Earth API exposes the
parseKml method. The parseKml
method of the GEPlugin class takes a KML string and returns a KmlFeature-derived
object that represents it.
As per the comparison table above,
parseKml differs from fetchKml in that the resulting
object is returned immediately. Below is an example of an
addKmlFromString method that will parse and display KML immediately
after the plugin is loaded::
function addKmlFromString(kmlString) {
var kmlObject = ge.parseKml(kmlString);
ge.getFeatures().appendChild(kmlObject);
}
...
addKmlFromString(
'<?xml version="1.0" encoding="UTF-8"?>' +
'<kml xmlns="http://www.opengis.net/kml/2.2">' +
' <Placemark>' +
' <name>Test Placemark</name>' +
' <Point>' +
' <coordinates>' +
' -122,37' +
' </coordinates>' +
' </Point>' +
' </Placemark>' +
'</kml>');
This method is often used as an alternative way to create Earth features, as
opposed to using object creation functions such as createPlacemark.
In some situations, it is faster and easier to call parseKml on a
KML string built up using JavaScript string operations, than to make the
equivalent Earth API calls. With parseKml, the bulk of the 'heavy
lifting' work is done by the plugin, which runs on native, compiled code.
This article showed some of the basic ways in which KML could be loaded in the Google Earth API. To learn more, visit the demo gallery or peruse the Earth API reference.