Introduction
Ever need to make pushpin maps of customers or store locations? Before you even build a map, you need to geocode the address information. Geocoding is the process of converting text address like 123 North Burgundy Street, Chicago, IL into longitude and latitude points that specify the pinpoint on a map grid. For years, this was a costly process involving third party GIS applications, quarterly data updates, and a high degree of IT expertise to keep things running. Thanks to services like Yahoo! Placefinder, you can geocode up to 5,000 addresses each day for free!
Background
Before you get started, you need to apply for an application ID from Yahoo! Placefinder. You can get the AppID here: http://developer.yahoo.com/geo/placefinder/. Paste the app ID you receive from Yahoo! in the Class_Initialize
section of the class. The class itself is very simple. The next section shows just how easy it is.
Using the code
Paste the class code below into your application. To call the geocoder, first create an instance of the class, then you make a call to the geocoder.
dim ygeo
dim lon
dim lat
set ygeo = new YGeoCoder
call ygeo.Geocode( address, city, state, zip )
if ygeo.iserror = false then
lon = ygeo.longitude
lat = ygeo.latitude
end if
The following properties are populated from the geocoder results after making a call to Geocode
:
street
- The street address passed; it may be corrected by Yahoo! geocoder and expressed in short-hand. city
- The city found upon geocoding (if only street address and zip are passed to the geocode request). state
- The state found upon geocoding (if only street address and zip are passed to the geocode request). zip
- The zip code found (if only street address, city, and state are passed to the geocode request). latitude
- the latitude portion of the geocoded address. longitude
- the longitude portion of the geocoded address. country
- the country of the geocoded address. xml
- the XML data returned from Yahoo! placefinder. reason
- if the geocode request fails, this will contain the reason.
The Code
class YGeoCoder
private appid
private m_street
private m_city
private m_state
private m_zip
private m_lon
private m_lat
private m_precision
private m_country
private m_xml
private m_reason
private m_output
private m_url
sub class_initialize()
appid=""
m_output = "xml"
end sub
property get output()
output = m_output
end property
property get url()
url = m_url
end property
property let output(value)
if value="php" or value="xml" then
m_output=value
else
m_output = "xml"
end if
end property
property get lon()
lon = m_lon
end property
property get lat()
lat = m_lat
end property
property get city()
city = m_city
end property
property get state()
state = m_state
end property
property get zip()
zip = m_zip
end property
property get country()
country = m_country
end property
property get precision()
precision = m_precision
end property
property get address()
address=m_street
end property
property get street()
street = m_street
end property
property get xml()
xml = m_xml
end property
property get reason()
reason = m_reason
end property
function GetPrecision( doc )
Dim node
dim value
set node=doc.documentElement.selectSingleNode( "/ResultSet/Result" )
if node is nothing then
value = "none"
else
value = node.GetAttribute( "precision" )
end if
set node = nothing
GetPrecision = value
end function
function GetXMLValue( doc, name )
Dim node
dim value
if left(name,1) = "/" then
set node=doc.documentElement.selectSingleNode( name )
else
set node=doc.documentElement.selectSingleNode("/ResultSet/Result/" & name )
end if
if node is nothing then
value = ""
else
value = node.text
end if
set node = nothing
GetXMLValue = value
end function
function geocode( street, city, state, zip )
dim url
Dim doc
output = m_output
Set doc=CreateObject("Microsoft.XMLDOM")
doc.async=false
call doc.setProperty("ServerHTTPRequest",true)
url="http://local.yahooapis.com/MapsService/V1/geocode" & _
"?appid=" & appid & _
"&street=" & street & _
"&city=" & city & _
"&state=" & state & _
"&zip=" & zip & _
"&output=" & output
m_url = url
doc.load( url )
m_lat = 0.0
m_lon = 0.0
m_street = ""
m_city = ""
m_state = ""
m_zip = ""
m_country = ""
m_xml = "not loaded"
m_precision = "failed"
if doc.parseError.errorcode=0 then
if isError( doc ) = true then
m_reason = GetXMLValue( doc, "/Error/Message" )
else
m_precision = GetPrecision( doc )
m_lat = GetXMLValue( doc, "Latitude" )
m_lon = GetXMLValue( doc, "Longitude" )
m_street = GetXMLValue( doc, "Address" )
m_city = GetXMLValue( doc, "City" )
m_state = GetXMLValue( doc, "State" )
m_zip = GetXMLValue( doc, "Zip" )
m_country = GetXMLValue( doc, "Country" )
m_reason = ""
end if
m_xml = doc.xml
else
m_reason = doc.parseError.reason & " line: " & doc.parseError.line
m_xml = doc.text
end if
set doc = nothing
end function
function isError( doc )
dim bResult
if GetXMLValue( doc, "/Error/Message" ) = "" then
bResult = false
else
bResult = true
end if
end function
end class
How It Works
The Geocode
function is the main workhorse in the class; it does the work of assembling a URL and making an HTTP GET call to the Yahoo! Placefinder service. Here is the code segment that does the job; I've added comments to each line describing what it does:
Set doc=CreateObject("Microsoft.XMLDOM")
doc.async=false
call doc.setProperty("ServerHTTPRequest",true)
url="<a href="http://local.yahooapis.com/MapsService/V1/geocode">http://local.yahooapis.com/MapsService/V1/geocode</a>" & _
"?appid=" & appid & _
"&street=" & street & _
"&city=" & city & _
"&state=" & state & _
"&zip=" & zip & _
"&output=" & output
m_url = url
doc.load( url )
The doc
object will now contain the XML response from Yahoo!'s Web Service. To populate the object properties, I parse the XML document, looking for each desired property value. To make this an easy task, I use a utility function GetXMLValue
that takes as parameters the document object and the name of the return tag whose value I want to capture. You'll see this as a series of calls that look like this...
m_lat = GetXMLValue( doc, "Latitude" )
In the example above, I get the latitude value and assign it to m_lat
. This is exposed to your calling code as the property .lat
in your ygeo
object. This practice might seem redundant, but it is the proper object oriented technique for dealing with classes. The following code segment illustrates how the property is created:
property get lat()
lat = m_lat
end property
The GetXMLValue
function is a shortcut way to get the desired properties. Below you will find the full function, with line by line comments that describe what each line is doing:
function GetXMLValue( doc, name )
Dim node
dim value
if left(name,1) = "/" then
set node=doc.documentElement.selectSingleNode( name )
else
set node=doc.documentElement.selectSingleNode("/ResultSet/Result/" & name )
end if
if node is nothing then
value = ""
else
value = node.text
end if
set node = nothing
GetXMLValue = value
end function
That covers the main set of functions that make this class work. There are two more functions worth noting: isError
and GetPrecision
. Each takes the XML document object as a parameter and returns a value based on what is found in the XML. isError
returns true
if Yahoo! Place Finder could not geocode the address for some reason (for example, if you passed all blank values). The GetPrecision
function returns Yahoo's precision value which indicates whether the longitude and latitude values are from the 'address
', 'zip
', or 'city
' depending on how accurately your address information could be matched. In the case of zip and city, the "centroid
" value is provided. The centroid in most cases is the geographic center of the city or the zip code's tabulated area.
History
- 2010/09/06 - Initial article post
- 2012/03/06 - Updated code for revised API