Google Maps, Google Earth, and the Geocoder
Google Maps has become the ubiquitous map technology on the Web, allowing users to instantly bring up geographical maps and pan and zoom around them, including 360-degree views of the street at eye-level. Google Earth provides a 3D photographic encyclopedia of the Earth, letting you pan and zoom an image of the Earth at various heights. With the Google Maps API, you can embed Google Maps into your own Web pages. Add KML, an XML language used to describe geographical information such as coordinates on the Earth, and you can overlay your own visual and textual data onto the maps. You can also import KML data into Google Earth, and project your own 3D data onto the Earth as the user pans and zooms.
For example, the musical group Nine Inch Nails released their most recent album, "The Slip" through download, and they have posted geographical download data that it produced using Google Earth and KML, as in Figure 1.
Figure 1. Download data for Nine Inch Nails' album "The Slip", rendered using Google Earth and KML

This brilliant concept hints at the possibilities available with Google's API and KML. The height of each spike reflects the number of downloads recorded at that location, and was created (one must assume), by creating a line in KML at the download's longitude and latitude, from altitude 0 to an altitude proportionate to the number of downloads at that location.
One critical detail missing from this visualization is the ability to map customer addresses, or at least postal codes, to their geographical coordinates on the Earth, because all custom KML data is positioned on the Earth using longitude, latitude and altitude coordinates.
To solve this problem, Google recently made available the Google Geocoder Web service, that takes a street address and returns KML data describing the address to whatever accuracy is possible, including its latitude and longitude. Once you have these coordinates you can overlay textual and visual data on 2D maps and the 3D globe as creatively as your imagination allows.
Getting started with the Google Maps API and Geocoder service
To use the Google Maps API and Google's Geocoder Web service, you must first sign up
for a Google Maps API key (see Resources for a link),
specifying the URL of the Web site that will be issuing API requests (you can sign up
for as many keys/URLs as you like). On the results page, you'll find your API key and a starter HTML page containing the JavaScript necessary to display a Google map, the core of which is the JavaScript function load() (see Listing 1), which is called when the page loads.
Listing 1. JavaScript function displaying a Google map within the page
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
}
}
|
This function makes sure the browser can display a Google Map, then creates a map
object (Gmap2), providing it with the HTML element in the
page to use as the map's container ("map"). It then sets its center to a coordinate on
Earth, using the GLatLng (latitude/longitude) parameter
object, and specifies a zoom depth (height) of 13. Figure 2 shows the resulting map.
Figure 2. Google map displayed by starter page

Providing overlay data using KML
You can use the JavaScript Google Maps API to overlay custom data, such as creating several bookmarks at locations or overlaying a few colored polygons and lines. However, for more complex data (that is, data containing many more data points), you will want to use a KML document. The KML document can specify geographic data including addresses, 3D coordinates on the Earth, and custom textual and visual data to be overlaid on maps or 3D models of the Earth.
When you provide KML data to Google Maps, you must use a URL that Google's servers can access to retrieve the KML, so you must provide the server-side KML. In this article series, you'll use server-side XSLT to transform a database of information into a KML file that you can feed to Google Maps and Google Earth to render custom data.
Storing Geocoder data in the database
The longitude and latitude of an address is useful with respect to Google Maps and Google Earth, but to obtain them, you must make a call to the Google Geocoder Web service. This can take some time, so when you store the address in the database it makes sense to store the longitude and latitude of the address along with it. This way you can query the database, directly producing XML, and use XSLT to transform the returned data directly into KML that you can overlay on a map.
To accomplish this, you have two options as to how you call the Geocoder service:
- Call the Geocoder server-side before recording the information in the database
- Use the JavaScript library provided by Google to call the Geocoder before you submit the form that contains the user's address information
First you will call the Geocoder from PHP, and use the SimpleXML module to traverse the
results. The recordListing() function takes the request
parameters for recording an apartment listing for a real estate brokerage, calls the
Geocoder service, and uses the result to obtain the postal code and geographical
coordinates of an address, recording all the information in the database (see Listing 2).
Listing 2. The
recordListing() function (PHP)
function recordListing($address, $aptNumber, $city, $state,
$aptType, $rent, $notes) {
$geocoder = new GoogleGeocoder(GOOGLE_MAPS_API_KEY);
$result = $geocoder->fetchAddress($address, $city, $state);
// use the geocoder to make sure the address is accurate enough to use
if ($result->getAccuracy() < GoogleGeocoderAccuracies::ADDRESS) {
throw new Exception ("Address does not have enough accuracy to record the listing.");
}
// store in the database
createListingInDb ($address, $aptNumber, $city, $state,
$result->getZipcode(),
$result->getLongitude(),
$result->getLatitude(),
$aptType, $rent, $notes);
}
|
The code in Listing 2 demonstrates another use of the Geocoder's result information—a data-integrity check. The Geocoder's result includes an Accuracy rating, measuring the specificity of the input. Here, recordListing() uses this accuracy measurement (explained in more detail after Listing 4 below) to confirm that the information is specific enough to record in the database.
To make the code reusable, encapsulate the call to Google's Geocoder in a GoogleGeocoder class (see Listing 3).
Listing 3. The
GoogleGeocoder class (PHP)
class GoogleGeocoder {
private $apiKey;
private $googleGeocoderUrl = 'http://maps.google.com/maps/geo?';
public function __construct ($apiKey) {
$this->apiKey = $apiKey;
}
public function fetchAddress ($address, $city, $state) {
// encode address for google api call (plusses, commas)
$fullAddress = $this->encodeAddress ($address, $city, $state);
// create the geocoder API call
$geocoderCall =
$this->googleGeocoderUrl .
"q=$fullAddress" .
"&key=$this->apiKey" .
"&output=xml";
$result = file_get_contents ($geocoderCall);
return new GoogleGeocoderResult($result);
}
private function encodeAddress($address, $city, $state) {
return urlencode (join (", ", array ($address, $city, $state)));
}
}
|
The GoogleGeocoder class is responsible for calling the
geocoder service through HTTP with a given street address. It takes your Google Maps
API key in its constructor for use in the HTTP call. FetchAddress() first encodes the address properly for the call, then
constructs the call's URL, providing the address as the q parameter, the Google Maps API key as the key parameter, and specifying output=xml. Your other output options here are json and csv, the latter of which will return a simplified comma-delimited response if all you need are the longitude and latitude. Finally, the function calls the URL using file_get_contents(), which will read a URL like a file if the string provided begins with a supported protocol such as HTTP.
The response KML of the GoogleGeocoder
service
The Google Geocoder service will return KML that describes the address. For example, for address "123 E. 34th St., New York, NY", the call returns the XML in Listing 4.
Listing 4. Geocoder response XML for "123 E. 34th St., New York, NY"
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Response>
<name>123 E. 34th St., New York, NY</name>
<Status>
<code>200</code>
<request>geocode</request>
</Status>
<Placemark id="p1">
<address>123 E 34th St, New York, NY 10016, USA</address>
<AddressDetails Accuracy="8"
xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0">
<Country>
<CountryNameCode>US</CountryNameCode>
<AdministrativeArea>
<AdministrativeAreaName>NY</AdministrativeAreaName>
<SubAdministrativeArea>
<SubAdministrativeAreaName>Manhattan<
/SubAdministrativeAreaName>
<Locality>
<LocalityName>New York</LocalityName>
<Thoroughfare>
<ThoroughfareName>123 E 34th St<
/ThoroughfareName>
</Thoroughfare>
<PostalCode>
<PostalCodeNumber>10016<
/PostalCodeNumber>
</PostalCode>
</Locality>
</SubAdministrativeArea>
</AdministrativeArea>
</Country>
</AddressDetails>
<Point>
<coordinates>-73.980182,40.746595,0</coordinates>
</Point>
</Placemark>
</Response>
</kml>
|
The response contains a Status reporting either success (code 200) or one of a number of error codes (see Resources for a link to a table of error codes on the Geocoder service page). The Placemark element represents the address you specified in the call, and provides a structured representation of that street address according to XAL, the eXtensible Address Language that can represent addresses from around the world (which is why the structure may seem so arcane—it has to handle so many different address structures for different countries).
The AddressDetails element also contains an Accuracy
attribute, denoting how specifically the XML describes a location on Earth. For
example, if you had only specified "New York, NY", you would get a lower Accuracy rating because the Geocoder has less information to work with and would be unable to provide more specific information about the address like the postal code. In that case, it provides a longitude and latitude correct for some point within New York State but not more specific than that. Accuracy is not a rating or degree of confidence in the result, but a measure of the specificity of the input.
For easier use of this XML response, GoogleGeocoder finally creates a GoogleGeocoderResult object to encapsulate the XML traversal as in Listing 5.
Listing 5. The
GoogleGeocoderResult class (PHP)
class GoogleGeocoderResult {
public function __construct ($xml) {
$this->xml = new SimpleXMLElement($xml);
$this->resultCode = intval($this->xml->Response->Status->code);
if ($this->resultCode != 200) {
throw new GoogleGeocoderException ($this->getResultCode());
}
$this->placemark = $this->xml->Response->Placemark[0];
$this->accuracy = intval($this->placemark->AddressDetails['Accuracy']);
$coordinates = $this->placemark->Point->coordinates;
$coordinatesSplit = explode(",", $coordinates);
$this->longitude = $coordinatesSplit[0];
$this->latitude = $coordinatesSplit[1];
$this->altitude = $coordinatesSplit[2];
}
public function getZipcode() {
if ($this->accuracy < GoogleGeocoderAccuracies::POST_CODE) {
throw new Exception ("Address does not have enough accuracy for zipcode.");
}
return $this->placemark->AddressDetails->Country->AdministrativeArea->
SubAdministrativeArea->Locality->PostalCode->PostalCodeNumber;
}
|
The GoogleGeocoderResult uses PHP's SimpleXML module to make accessing the XML structure nearly trivial. SimpleXML maps an XML document's element tree into a PHP object tree, representing sub-elements as properties. SimpleXMLElement takes an XML string and then effectively turns the XML sub-elements into PHP properties of the SimpleXMLElement object. If the XML element in question contains attributes, you can also access the SimpleXMLElement as a PHP associative array, where each key in the array represents an attribute on the XML element.
First, the GoogleGeocoderResult constructor obtains the response code from the SimpleXMLElement:
$this->resultCode = intval($this->xml->Response->Status->code); |
The $this->xml portion shown here is the SimpleXMLElement created from the XML document. When you access its
Response property, it returns a SimpleXMLElement object
that represents the Response element in the KML response (the top-level
SimpleXMLElement represents the top-level KML element in the XML tree). If an element
contains more than one sub-element of the same name, those sub-elements will be turned
into an array property. For example, suppose the Geocoder response returned multiple codes within the State element, you would access the first one with $this->xml->Response->Status->code[0]. SimpleXMLElement also converts transparently into a PHP string, so that you can pass the code element directly into intval() to convert it to a number, rather than call a method on it to obtain its text value.
After obtaining the response code, if it is not 200, this constructor throws a GoogleGeocoderException (see the example code) that maps the Geocoder error code into the appropriate error message (copied directly from the reference table on Google's site).
Then the constructor holds onto the Placemark element (as a SimpleXMLElement object) to represent the specified location on
Earth. All other information that you want is from elements under this one. Note that
Placemark is accessed here as an array. The Geocoder's response might contain
multiple Placemarks for a given address, but SimpleXML lets you access any element as
an array because it can't tell from just the XML whether to interpret the element as an array or a single object.
Next it obtains the Accuracy of the response, obtaining the value of the Accuracy attribute of the AddressDetails element:
$this->accuracy = intval($this->placemark->AddressDetails['Accuracy']); |
The SimpleXMLElement makes attribute values available as
associative array properties on the SimpleXMLElement
itself—SimpleXMLElement is effectively a string, an
associative array, and a SimpleXMLElement object at once,
allowing for such elegant syntax when traversing the XML tree. The constructor then obtains the longitude and latitude coordinates of the location, which appear in the result as <coordinates>73.980182,40.746595,0</coordinates>—longitude, latitude, altitude (altitude is always zero when you look up an address).
To obtain the postal code, getZipcode() first makes sure
that the response is accurate enough to contain one, using the GoogleGeocoderAccuracies class, which contains constants for each of the Accuracy values found in Google's reference documentation (see Resources).
Calling the Geocoder from JavaScript
As an alternative to calling the Geocoder from PHP, you can call it using the GClientGeocoder JavaScript provided in the Google Maps API library.
Then, use the response information to set hidden inputs in the form before you submit it to the server. Listing 6 demonstrates how you might do this.
Listing 6. Calling the Geocoder from JavaScript
function onSubmitAddressForm() {
var addressInput = document.getElementById('addressInput');
var cityInput = document.getElementById('cityInput');
var stateInput = document.getElementById('stateInput');
var fullAddress = addressInput.value + ", " + cityInput.value + ", "
+ stateInput.value;
var geocoder = new GClientGeocoder();
geocoder.getLocations(fullAddress, submitAddressFromGeocoderResponse);
}
|
This uses the HTML form found in add-address.php (see Downloads) containing the address, city, and state text inputs
to submit, and a button such as <button
onclick="onSubmitAddressForm()">Submit</button>, that calls this function to
handle the form submission. The onSubmitAddressForm() function obtains the building address, city, and state from the form elements, creates the complete address string from them, creates a new GClientGeocoder object, and calls its getLocations() method, passing in the full address to look up and the callback function to call with the response object (see Listing 7).
Listing 7. Using the Geocoder
callback response in JavaScript
function submitAddressFromGeocoderResponse(response) {
if (! response || response.Status.code != 200) {
alert("Geocoder did not recognize address. Code = " + response.Status.code);
} else {
var coordinates = response.Placemark[0].Point.coordinates;
var longitude = coordinates[0];
var latitude = coordinates[1];
document.getElementById('longitudeInput').value = longitude;
document.getElementById('latitudeInput').value = latitude;
document.getElementById('addressForm').submit();
}
}
|
GClientGeocoder calls the submitAddressFromGeocoderResponse function when it receives the
response of the Geocoder service, which is in JavaScript Object Notation (JSON) format
(see Resources for more information). JSON is the
increasingly preferred alternative to XML when fetching hierarchical data from
JavaScript because it provides a concise, human-readable, and unambiguous
representation for a JavaScript object tree that has the same structure as the
corresponding XML response data shown earlier. You can see an example of the JSON
response structure in Google's reference documentation (see Resources). Note that the Placemark element is actually an array
of Placemarks, as multiple Placemarks might correspond to an address.
SubmitAddressFromGeocoderResponse checks the response's status code just as the PHP code did, and retrieves the coordinates value using the same object structure as when using SimpleXML. It then sets hidden input values in the page's form and submits the form programmatically for storage in the database.
You have now completed the first part of your application. You called the Geocoder service and stored the coordinate information in the database. In Part 2 you'll use stored procedures to produce XML data from a MySQL query, XSLT to transform that data into KML overlay data, and the Google Maps API to display the KML on a map embedded in your Web site.
| Description | Name | Size | Download method |
|---|---|---|---|
| Part 1 example source code | google-maps-series-code.tar | 100KB | HTTP |
Information about download methods
Learn
- Overlay data on maps using
XSLT, KML, and the Google Maps API, Part 2: Transform and use the data (Jake Miles, developerWorks,
September 2008): With Google's Geocoder Web service, look up postal codes and address coordinates for
storage in a database. Add XSLT and KML to overlay a map with the locations in an example app for a real
-estate brokerage.
- KML Tutorial: Learn about KML, a file format used to display geographic data in an Earth browser such as Google Earth, Google Maps, and Google Maps for mobile, in this great tutorial.
- Google Maps API sign up: Sign up for a Google Maps API key.
- Introducing Google's
Geocoding Service: Learn about the newest addition to the Google Maps API and map
locations by converting mailing addresses to their corresponding coordinates (and skip third-party solutions).
- Google's
reference documentation: Read more on how to extract structured addresses.
- Google Maps API Reference: Find the error codes for the Geocoder service response.
- JSON: Explore this increasingly preferred alternative to XML when fetching hierarchical data from JavaScript.
- PHP.net: Visit the central resource for PHP developers.
- Google's
reference documentation: Learn about the
GoogleGeocoderAccuraciesclass, which contains constants for each of the Accuracy values. - A
(Re)-Introduction to JavaScript (Simon Willison, March 2006): Take a fresh at JavaScript and what you can do with it.
- Recommended
PHP reading list (Daniel Krook and Carlos Hoyos, developerWorks, March 2006): Learn about PHP with this reading list compiled for programmers and administrators by IBM Web application developers.
- Learning
PHP (Tyler Anderson and Nicholas Chase, developerWorks, June-July 2006): Read this series to learn how to program with PHP.
- Be sure to check out these: Tutorial: Introduction to JavaScript and Introduction to JavaScript from w3schools.com.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- The technology
bookstore: Browse for books on these and other technical topics.
- developerWorks
podcasts: Listen to interesting interviews and discussions for software developers.
Get products and technologies
- IBM
trial software for product evaluation: Build your next project with trial software available for download directly from developerWorks, including application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- XML zone discussion forums: Participate in any of several XML-related discussions.
- developerWorks XML zone: Share your thoughts: After you read this article, post your comments and thoughts in this forum. The XML zone editors moderate the forum and welcome your input.
- developerWorks blogs: Check out these blogs and get involved in the developerWorks community.

Jake Miles is a senior developer at Conde Nast, currently working with Facebook, Myspace and OpenSocial applications, using Java, PHP, Adobe Flex and JavaScript. He has been working as a professional developer for 10 years and has been an avid student and tinkerer since he was 10. He also teaches on a volunteer basis.




