Friday 29 March 2013

Bite-sized free geocoding

            It took me some time to read (or skim through) all the TOUs of different geocoding providers. Most of them are free for personal use (Yahoo maps/Google maps and Bing maps geocoders). Only one that I found is free for commercial use (although with some heavy constraints but still). It's called Nominatim and it is used by OpenStreetMap project. I wrote this short snippet, someone might find helpful. First, we need to create the request url. The method below might not be an example of good coding practices, but it's clear enough. What you want to get as the return value is an url that looks something like this:
                http://nominatim.openstreetmap.org/search?city=London&format=xml
  1 public string BuildRequest(string building, string street, string city,
  2  string country) 
  3  { 
  4     bool streetAdded, cityAdded, countryAdded;
  5     streetAdded = cityAdded = countryAdded = false;
  6   
  7     StringBuilder sb = 
  8     new StringBuilder(@"http://nominatim.openstreetmap.org/search?"); 
  9  
 10     if (!String.IsNullOrEmpty(street)) 
 11     { 
 12         sb.Append("street="); 
 13         if (!String.IsNullOrEmpty(building))
 14         { 
 15             sb.AppendFormat("{0} ", building); 
 16         } 
 17         sb.Append(street); 
 18         streetAdded = true; 
 19     } 
 20  
 21     if (!String.IsNullOrEmpty(city)) 
 22     { 
 23         if (streetAdded) 
 24             sb.Append("&"); 
 25  
 26         sb.AppendFormat("city={0}", city); 
 27         cityAdded = true; 
 28     } 
 29  
 30     if (!String.IsNullOrEmpty(country)) 
 31     { 
 32         if (streetAdded | cityAdded) 
 33             sb.Append("&"); 
 34  
 35         sb.AppendFormat("country={0}", country); 
 36         countryAdded = true; 
 37     } 
 38  
 39     if (streetAdded | cityAdded | countryAdded)
 40         sb.AppendFormat("&"); 
 41  
 42     sb.AppendFormat("format=xml"); 
 43     return sb.ToString();  
 44  }

             After formulating the request, we can pass it into DownloadString() method. What we'll get in return will be xml in string form. Each <place> node is a separate place which matches the address we've given. There are several formats we can choose from when working with Nominatim provider, I've chosen xml.




  1 public Point GetCoordinates(string building, string street, string city,
  2  string country) 
  3 {     
  4     WebClient webClient = new WebClient();    
  5     string request = BuildRequest(building, street, city, country); 
  6     string result = webClient.DownloadString(request);
  7  
  8     XmlDocument xml = new XmlDocument(); 
  9     xml.LoadXml(result); 
 10  
 11     var nodes = xml.SelectNodes("/searchresults/place"); 
 12  
 13     if (nodes != null && nodes.Count > 0)
 14     { 
 15         var lat = nodes[0].Attributes["lat"].InnerText; 
 16         var lon = nodes[0].Attributes["lon"].InnerText; 
 17  
 18         double latitude = Double.Parse(lat, CultureInfo.InvariantCulture);
 19         double longitude = Double.Parse(lon, CultureInfo.InvariantCulture);
 20         return new Point(latitude, longitude);
 21     } 
 22     return null;
 23 } 


         To use the WebClient class, you need to add reference to System.Net. To get more information about the xml data returned by the provider, and the data you can pass in the request you should visit: http://wiki.openstreetmap.org/wiki/Nominatim To see the exact usage policy check: http://wiki.openstreetmap.org/wiki/Nominatim_usage_policy As you can see this is a really easy way, if you want to implement some simple geocoding in your app.

No comments:

Post a Comment