require 'open-uri' require 'rexml/document' module Ym4r module GmPlugin module Geocoding GEO_SUCCESS = 200 GEO_MISSING_ADDRESS = 601 GEO_UNKNOWN_ADDRESS = 602 GEO_UNAVAILABLE_ADDRESS = 603 GEO_BAD_KEY = 610 GEO_TOO_MANY_QUERIES = 620 GEO_SERVER_ERROR = 500 #Gets placemarks by querying the Google Maps Geocoding service with the +request+ string. Options can either an explicity GMaps API key (:key) or a host, (:host). def self.get(request,options = {}) api_key = ApiKey.get(options) sensor = options[:sensor] || false output = options[:output] || "kml" output_encoding = options[:output_encoding] || "utf-8" url = "http://maps.google.com/maps/geo?q=#{URI.encode(request)}&key=#{api_key}&sensor=#{sensor}&output=#{output}&oe=#{output_encoding}" res = open(url).read case output.to_sym when :json res = eval(res.gsub(":","=>")) #!!!EVAL EVAL EVAL EVAL!!! hopefully we can trust google... placemarks = Placemarks.new(res['name'],res['Status']['code']) if res['Placemark'] placemark = res['Placemark'] placemark.each do |data| data_country = data['Country']['CountryNameCode'] rescue "" data_administrative = data['Country']['AdministrativeArea']['AdministrativeAreaName'] rescue "" data_sub_administrative = data['Country']['AdministrativeArea']['SubAdministrativeArea']['SubAdministrativeAreaName'] rescue "" data_locality = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['LocalityName'] rescue "" data_dependent_locality = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality']['DependentLocalityName'] rescue "" data_thoroughfare = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality']['Thoroughfare']['ThoroughfareName'] rescue "" data_postal_code = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality']['Thoroughfare']['PostalCode']['PostalCodeNumber'] rescue "" lon, lat = data['Point']['coordinates'][0,2] data_accuracy = data['Accuracy'] unless data_accuracy.nil? data_accuracy = data_accuracy.to_i end placemarks << Geocoding::Placemark.new(data['address'], data_country, data_administrative, data_sub_administrative, data_locality, data_dependent_locality, data_thoroughfare, data_postal_code, lon, lat, data_accuracy) end end when :kml, :xml doc = REXML::Document.new(res) response = doc.elements['//Response'] placemarks = Placemarks.new(response.elements['name'].text,response.elements['Status/code'].text.to_i) response.elements.each(".//Placemark") do |placemark| data = placemark.elements data_country = data['.//CountryNameCode'] data_administrative = data['.//AdministrativeAreaName'] data_sub_administrative = data['.//SubAdministrativeAreaName'] data_locality = data['.//LocalityName'] data_dependent_locality = data['.//DependentLocalityName'] data_thoroughfare = data['.//ThoroughfareName'] data_postal_code = data['.//PostalCodeNumber'] lon, lat = data['.//coordinates'].text.split(",")[0..1].collect {|l| l.to_f } data_accuracy = data['.//*[local-name()="AddressDetails"]'].attributes['Accuracy'] unless data_accuracy.nil? data_accuracy = data_accuracy.to_i end placemarks << Geocoding::Placemark.new(data['address'].text, data_country.nil? ? "" : data_country.text, data_administrative.nil? ? "" : data_administrative.text, data_sub_administrative.nil? ? "" : data_sub_administrative.text, data_locality.nil? ? "" : data_locality.text, data_dependent_locality.nil? ? "" : data_dependent_locality.text, data_thoroughfare.nil? ? "" : data_thoroughfare.text, data_postal_code.nil? ? "" : data_postal_code.text, lon, lat, data_accuracy ) end end placemarks end #Group of placemarks returned by the Geocoding service. If the result is valid the +status+ attribute should be equal to Geocoding::GE0_SUCCESS class Placemarks < Array attr_accessor :name,:status def initialize(name,status) super(0) @name = name @status = status end end #A result from the Geocoding service. class Placemark < Struct.new(:address,:country_code,:administrative_area,:sub_administrative_area,:locality,:dependent_locality,:thoroughfare,:postal_code,:longitude,:latitude,:accuracy) def lonlat [longitude,latitude] end def latlon [latitude,longitude] end end end end end