Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

XQuery/Google Geocoding

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

Motivation You have one or more geographic names and you want to create a map of these locations. Method We will use a Google RESTful web service to return geographical data from a list of place names. Google provides an HTTP-based Geocoding service. This requires registration of a site for a API key and there are limitations on the usage of this API. Results can be returned in XML or JSON. Querying Google's API The following script takes a location and returns the xml from the service: let $key := "apikey" let $location := request:get-parameter("location",()) let $location := escape-uri($location,false()) let $url := concat("https://maps.googleapis.com/maps/api/geocode/xml?address=",$location,"&key=",$key) let $response := doc($url) return $response </source > ==== Examples ==== Single City Examples: * [http://kitwallace.co.uk/xqbook/geo/googlegeocode.xq?location=Minneapolis Minneapolis] - example using a single city with no country * [http://kitwallace.co.uk/xqbook/geo/googlegeocode.xq?location=Bristol,UK Bristol,UK] - example using a city and country Multiple matches may be returned: * [http://kitwallace.co.uk/xqbook/geo/googlegeocode.xq?location=Bristol Bristol] * or a false positive: [http://kitwallace.co.uk/xqbook/geo/googlegeocode.xq?location=Santas+House Santa's House] In the UK, this service will geocode postcodes: * [http://kitwallace.co.uk/xqbook/geo/googlegeocode.xq?location=BS3+4EA Bristol Hackspace] == Response as KML == The XML response can be reformated as a KML file. Note the addition of the relevant media-type for KML . <syntaxhighlight lang="xml"> let $key := "my apikey" let $location := request:get-parameter("location",()) let $location := escape-uri($location,false()) let $url := concat("https://maps.googleapis.com/maps/api/geocode/xml?address=",$location,"&key=",$key) let $response := doc($url)/GeocodeResponse return if ($response/status="OK") then let $x := response:set-header('Content-disposition',concat('inline;filename="',$location,'.kml";')) let $result := $response/result[1] let $serialize := util:declare-option("exist:serialize", "method=xml media-type=application/vnd.google-earth.kml+xml indent=yes") return <kml> <Folder> <name>{$location}</name> {for $result in $response/result return <Placemark> <name>{string($result/formatted_address)}</name> <Point> <coordinates>{$result/geometry/location/lng/string()},{$result/geometry/location/lat/string()},0</coordinates> </Point> </Placemark> } </Folder> </kml> else $response If you have GoogleEarth, this should load an overlay showing multiple Bristol locations: Bristol KML GoogleMap A simple way to view the generated kml is to use GoogleMaps. This script simply constructs the relevant URL to use the script above and then redirects to that URL: let $location := request:get-parameter("location",()) let $wikiurl := escape-uri(concat("http:/kitwallace.co.uk/geocodekml.xq?location=",$location),false()) let $url := concat("http://maps.google.co.uk/maps?q=",$wikiurl) return response:redirect-to(xs:anyURI($url)) Sadly this approach no longer works with GoogleMap - see support lost Bristol An alternative approach is to use GoogleMap's JavaScript API. Note that to embed JavaScript requires doubling { so it is generally easier to put the Javascript in a separate file. This approach makes use of any existing kml overlay and is simpler, but more restricted than implementing the map using the JavaScript API declare option exist:serialize "method=xhtml media-type=text/html"; let $location := request:get-parameter("location",()) let $url := escape-uri(concat("http://kitwallace.co.uk/xqbook/geo/geocodekml.xq?location=",$location),false()) return <html> <head> <script src="https://maps.googleapis.com/maps/api/js?v=3&key=myapikey"></script> <script type="text/javascript"> function initialize(url) {{ var map = new google.maps.Map(document.getElementById("map_canvas")); var kmlLayer = new google.maps.KmlLayer({{ url: url, map:map }}); }} </script> </head> <body onload="initialize('{$url}')"> <h2>Map of {$location}</h2> <div id="map_canvas" style="height: 80%;width: 80%; margin: 0px; padding: 0px"> </div> </body> </html> Examples * Bristol * London [Setting the zoom level doesn't seem to work] Data to overlay Often the locations are defined in a data file. The following script reads a local file of (a sample of ) whisky distilleries and creates a KML overlay. let $key := "apikey" let $locations := doc("/db/apps/xqbook/geo/whisky.xml") let $serialize := util:declare-option("exist:serialize", "method=xml media-type=application/vnd.google-earth.kml+xml") let $x := response:set-header('Content-disposition','inline;filename=whisky.kml') return <kml> <Folder> <name>Distilleries</name> {for $location in $locations//Whisky let $url := concat("https://maps.googleapis.com/maps/api/geocode/xml?address=",$location/Postcode,"&key=",$key) let $response := doc($url)/GeocodeResponse let $result := $response/result[1] return <Placemark> <name>{$location/Brand/string()}</name> <description>{$location/Address/string()}</description> <Point> <coordinates>{$result/geometry/location/lng/string()},{$result/geometry/location/lat/string()},0</coordinates> </Point> </Placemark> } </Folder> </kml> Whisky overlay and a modified version of the JavaScript can use the output to create a Whisky map