KML is an XML-based file format for displaying data in an Earth browser such as Google Earth or Google Maps. KML data can be generated within Google Earth itself, by hand-crafting KML files, or by writing programs that generate a well-formated KML document.
The goal of this tutorial is to introduce you to Google Earth, discuss the basic features of a KML file, and write a simple program that generates a KML file.
Google Earth is available within the LabNet environment. If you would like to run it from home, it can be downloaded from http://earth.google.com.
Within Google Earth, you can easily adjust the view and explore the data:
Other features include:
There are controls across the top of the display for:
Adding a feature to the map using these tools results in it being added to My Places. These features can be converted to a KML format by simply selecting the feature, selecting the copy command (control-c), and then pasting the results into a text editor. This makes it very easy to generate new content to be loaded into Google Earth
KML is an XML file format for representing data within Google Earth, Google Maps, and other geographical visualization tools. The basic file format is very simple:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>Example 1</name>
<Placemark>
<name>St. John's, NL</name>
<description>St. John's, NL is home to the Memorial University of Newfoundland.</description>
<Point>
<coordinates>-52.701129,47.576727,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
Coordinates are given by degrees of longitude, degrees of latitude, and elevation. Note that in Google Earth, the location of your pointer is displayed at the bottom of the screen. The default format is in degrees, minutes, seconds. You can change this to decimal degrees in the preferences.
The <description> of the <Placemark> can include HTML tag elements as well. However, since the HTML tags use a similar format to the KML tags, we need to either encode the HTML tags (i.e., replace < with <), or wrap the chunk of HTML in a special XML structure called CDATA. CDATA tells the XML parser to treat the enclosed text as data; as a result, the data is not parsed as XML.
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>Example 2</name>
<Placemark>
<name>Memorial University of Newfoundland</name>
<description>
<![CDATA[
<p>The <em>Memorial University of Newfoundland</em> is located in <strong>St. John's, NL</strong>.</p>
]]>
</description>
<Point>
<coordinates>-52.7352,47.5744,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
When adding a <Placemark>, the default method for representing this data in Google Earth is to provide a yellow pin and a label. While this is an appropriate visual encoding for things like locations, it is not very interesting from an information visualization perspective. Luckily, KML supports the generation of other simple geometric structures, using the <LineString> and <Polygon> tags.
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>Example 3</name>
<Style id="yellowLineGreenPoly">
<LineStyle>
<color>7f00ffff</color>
<width>4</width>
</LineStyle>
<PolyStyle>
<color>7f00ff00</color>
</PolyStyle>
</Style>
<Style id="bluePoly">
<PolyStyle>
<color>ffffc7ae</color>
</PolyStyle>
</Style>
<Placemark>
<name>A Walk on Campus</name>
<description>Transparent green wall with yellow outlines.</description>
<styleUrl>#yellowLineGreenPoly</styleUrl>
<LineString>
<extrude>1</extrude>
<tessellate>0</tessellate>
<altitudeMode>relativeToGround</altitudeMode>
<coordinates>
-52.73527816474198,47.57399154943812,1
-52.73543498943292,47.5738706315606,1
-52.73534531356528,47.57373486721405,1
-52.7352109398205,47.57361427318543,1
-52.73514380837204,47.57347870610806,1
-52.73514383568266,47.57335876540706,1
</coordinates>
</LineString>
</Placemark>
<Placemark>
<name>Box</name>
<description>Blue box in the middle of the street.</description>
<styleUrl>#bluePoly</styleUrl>
<Polygon>
<extrude>0</extrude>
<tessellate>1</tessellate>
<altitudeMode>clampToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-52.73523169111418,47.57380749695798,0
-52.73523169111418,47.57390749695798,0
-52.73533169111418,47.57390749695798,0
-52.73533169111418,47.57380749695798,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>
The <extrude>specifies whether vertical surfaces should be added between the shape and the surface of the Earth. The <LineString> above has this option turned on, making the shape three dimensional. The <Polygon> above has it turned off, making the shape a two-dimensional plane hovering 1 meter above the ground.
Other tags of interest are:
<altitudeMode>
<coordinates> are interpretedclampToGround -- ignore the altituderelativeToGround -- altitude is relative to the altitude of the terrain at that pointabsolute -- altitude is relative to sea level<tessellate>
<altitudeMode> of clampToGround<styleUrl>
Styles are specified within <Style> tags. Each <Style> tag must have an id assigned to it, so that it can be referenced from other elements such as <LineString> and <Polygon> elements. <LineStyle> elements describe how to draw <LineString> objects, and <PolyStyle> elements describe how to draw <Polygon> objects.
<color> elements describe a colour using four hexadecimal values:
Note that these colour values are backwards from the normal RGBA specification of colour values.
Custom icons can be added to placemarks within the KML file. Icons function differently than geometric objects in Google Earth. Their size remains constant at all but the highest altitudes of view (at which point they shrink and then disappear).
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>Example 4</name>
<Style id="redIcon">
<IconStyle>
<Icon>
<href>http://www.cs.mun.ca/~hoeber/teaching/cs4767/notes/02.1-kml/redicon.png</href>
</Icon>
</IconStyle>
</Style>
<Style id="greenDotIcon1">
<IconStyle>
<color>9900ff00</color>
<scale>1.5</scale>
<Icon>
<href>http://www.cs.mun.ca/~hoeber/teaching/cs4767/notes/02.1-kml/circle.png</href>
</Icon>
</IconStyle>
</Style>
<Style id="greenDotIcon2">
<IconStyle>
<color>ff00ff00</color>
<scale>1</scale>
<Icon>
<href>http://www.cs.mun.ca/~hoeber/teaching/cs4767/notes/02.1-kml/circle_border.png</href>
</Icon>
</IconStyle>
</Style>
<Placemark>
<name>Dr. Orland Hoeber</name>
<description>ER-6037</description>
<styleUrl>#redIcon</styleUrl>
<Point>
<coordinates>-52.7348,47.5737,0</coordinates>
</Point>
</Placemark>
<Placemark>
<styleUrl>#greenDotIcon1</styleUrl>
<Point>
<coordinates>-52.7353,47.5741,0</coordinates>
</Point>
</Placemark>
<Placemark>
<styleUrl>#greenDotIcon2</styleUrl>
<Point>
<coordinates>-52.7343,47.5741,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
The <IconStyle> tag is used to specify an icon within a named <Style> tag. An <IconStyle> tag can contain the following:
<Icon>
<href>tag<Color>
<scale>
Sample icons:


Since KML is simply an XML file, we can use a programming language such as Java to generate KML files to suit our needs. For example, we may have a list of geographic locations within a text file that we would like marked on the map. Rather than building the XML file by hand (as we have been doing up to this point), we now want to write a program that will read in the data and write out the proper KML file. In effect this program performs a simple data transformation (from a list-based format to an XML format).
To make building the XML file simpler, we will use JDOM (a Java library that simplifies reading and writing XML files). JDOM can be downloaded from: http://www.jdom.org
Once you have downloaded JDOM, select an existing project or create a new project in Eclipse, and place the the jdom.jar file (located in the build directory) in the lib directory. This will ensure that your Eclipse project can access the library.
The main features of JDOM that we are going to use here are:
org.jdom.Namespace
org.jdom.Document
org.jdom.Element
setAttribute is used to set attributes in the element tagsetText is used to set the text contents for the element tagaddContent is used to nest other Elements (tags) within this tagorg.jdom.output.Format
org.jdom.output.XMLOutputter
The data file contains location names, dates, and geographic locations:
Marysburg, SK; 1971 - 1989; -105.072,52.3176,0 Jasper, AB; 1989; -118.079,52.8882,0 Saskatoon, SK; 1989 - 1998; -106.647,52.123,0 Vancouver, BC; 1998 - 2002; -123.238,49.259,0 Regina, SK; 2002 - 2007; -104.621,50.4429,0 St. John's, NL; 2007 - now; -52.7101,47.564,0
The Java program reads in this data and generates a valid KML file using JDOM:
/**
* Program to read locations from a text file and generate a KML
* file that places icons and labels at those locations
*/
package kml;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
/**
* @author hoeber
*
*/
public class KmlSample {
static String inputFile = "data/kmlexample.txt";
static String outputFile = "data/output.kml";
public static void main(String[] args) {
/*
* Step 1: generate XML stub
*/
Namespace ns = Namespace.getNamespace("", "http://earth.google.com/kml/2.2");
// kml
Element kml = new Element("kml", ns);
Document kmlDocument = new Document(kml);
// Document
Element document = new Element("Document", ns);
kml.addContent(document);
// name
Element name = new Element("name", ns);
name.setText("Java Generated KML Document");
document.addContent(name);
/*
* Step 2: add in Style elements
*/
// Style
Element style = new Element("Style", ns);
style.setAttribute("id", "redIcon");
document.addContent(style);
// IconStyle
Element iconStyle = new Element("IconStyle", ns);
style.addContent(iconStyle);
// color
Element color = new Element("color", ns);
color.setText("990000ff");
iconStyle.addContent(color);
// Icon
Element icon = new Element("Icon", ns);
iconStyle.addContent(icon);
// href
Element href = new Element("href", ns);
href.setText("http://www.cs.mun.ca/~hoeber/teaching/cs4767/notes/02.1-kml/circle.png");
icon.addContent(href);
/*
* Step 3: read data from source location and
* add in a Placemark for each data element
*/
File file = new File(inputFile);
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(file));
try {
String line = reader.readLine();
while (line != null) {
String[] lineParts = line.split(";");
if (lineParts.length == 3) {
// add in the Placemark
// Placemark
Element placemark = new Element("Placemark", ns);
document.addContent(placemark);
// name
Element pmName = new Element("name", ns);
pmName.setText(lineParts[0].trim());
placemark.addContent(pmName);
// description
Element pmDescription = new Element("description", ns);
pmDescription.setText(lineParts[1].trim());
placemark.addContent(pmDescription);
// styleUrl
Element pmStyleUrl = new Element("styleUrl", ns);
pmStyleUrl.setText("#redIcon");
placemark.addContent(pmStyleUrl);
// Point
Element pmPoint = new Element("Point", ns);
placemark.addContent(pmPoint);
// coordinates
Element pmCoordinates = new Element("coordinates", ns);
pmCoordinates.setText(lineParts[2].trim());
pmPoint.addContent(pmCoordinates);
}
// read the next line
line = reader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
/*
* Step 4: write the XML file
*/
try {
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
FileOutputStream writer = new FileOutputStream(outputFile);
outputter.output(kmlDocument, writer);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}