KML 中使用的地理編碼地址

Google 地理團隊 Mano Marks
作者:2007 年 12 月
更新日期:2013 年 12 月

目標

本教學課程適用於熟悉指令碼語言的開發人員,且想要瞭解如何使用 Google Geocoding API 為地址進行地理編碼,並將這些地址整合至 KML 檔案。雖然程式碼範例是在 Python 中呈現,但也能輕鬆適應大多數其他程式設計語言。

「地理編碼」是將地址轉換為一組經緯度座標的程序,能讓您在地圖上顯示地址。您可以針對地址進行地理編碼,並直接將這些地址放入 KML 檔案這很常見,例如在表單中輸入資料時,而且您為了回應要求而產生 KML 檔案。這些 KML 檔案可以儲存在資料庫或檔案系統中,也可以傳回與檔案連結的 NetworkLink。請注意,使用這項技術時,您必須遵守 Geocoding API 的《服務條款》,因為儲存結果的時間有一些限制,以及您每天可以進行剖析的元素數量。

本教學課程說明如何使用 Python 擷取「1600 Amphitheatre Pkwy, Mountain View, CA 94043」字串,並將其轉換為字串:

<?xml version='1.0' encoding='UTF-8'?> 
<kml xmlns='http://earth.google.com/kml/2.2'>
<Document>
<Placemark>
<description>1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA</description>
<Point>
<coordinates>-122.081783,37.423111,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>

建立 KML 文件

KML 是 XML 標記語言,因此我們可以使用 Python 內建的 xml.dom.minidom 函式建立 KML 文件。Python 的最簡單之處為 DOM 實作,且大多數程式設計語言都支援 DOM,因此這項程序應可輕鬆轉移至其他程式設計語言。步驟如下:

  1. 使用 Python 的 xml.dom.minidom.Document() 建立文件。
  2. 使用 createElementNS. 建立根 <kml> 元素
  3. 使用 appendChild 將文件附加到文件。
  4. 使用 createElement 建立 Document 元素。
  5. 使用 appendChild 將其附加到 <kml> 元素。
  6. 針對每個位址,使用 createElement 建立 <Placemark> 元素,並將其附加至 Document 元素。接著建立 <description> 元素,並為其指派位址的值,然後將該元素附加到 <Placemark> 元素中。
  7. 建立 <Point> 元素,新增子項 <coordinates> 元素並附加至 <Placemark> 元素。
  8. 將地址傳送到 Maps API 地理編碼器;這個地理編碼器會以 JSON 或 XML 傳送回應。使用 urllib.urlopen() 擷取檔案並讀取為字串。
  9. 剖析回應並擷取經度和緯度元素。
  10. <coordinates> 元素中建立文字節點,並將經度/緯度字串指定為其值。
  11. 將 KML 文件寫入文字檔案。

Python 程式碼範例

請注意,以下程式碼範例使用的是虛擬 mapsKey 變數,您需要將這個金鑰替換成自己的金鑰

以下示範使用 Python 2.7 和 JSON 輸出進行地理編碼的程式碼範例:

import urllib
import xml.dom.minidom
import json 

def geocode(address, sensor=False):
 # This function queries the Google Maps API geocoder with an
 # address. It gets back a csv file, which it then parses and
 # returns a string with the longitude and latitude of the address.

 # This isn't an actual maps key, you'll have to get one yourself.
 # Sign up for one here: https://code.google.com/apis/console/
  mapsKey = 'abcdefgh'
  mapsUrl = 'https://maps.googleapis.com/maps/api/geocode/json?address='
     
 # This joins the parts of the URL together into one string.
  url = ''.join([mapsUrl,urllib.quote(address),'&sensor=',str(sensor).lower()])
#'&key=',mapsKey])
  jsonOutput = str(urllib.urlopen(url).read ()) # get the response 
  # fix the output so that the json.loads function will handle it correctly
  jsonOutput=jsonOutput.replace ("\\n", "")
  result = json.loads(jsonOutput) # converts jsonOutput into a dictionary 
  # check status is ok i.e. we have results (don't want to get exceptions)
  if result['status'] != "OK": 
    return ""
  coordinates=result['results'][0]['geometry']['location'] # extract the geometry 
  return str(coordinates['lat'])+','+str(coordinates['lng'])

def createKML(address, fileName):
 # This function creates an XML document and adds the necessary
 # KML elements.

  kmlDoc = xml.dom.minidom.Document()
  
  kmlElement = kmlDoc.createElementNS('http://earth.google.com/kml/2.2','kml')

  kmlElement = kmlDoc.appendChild(kmlElement)

  documentElement = kmlDoc.createElement('Document')
  documentElement = kmlElement.appendChild(documentElement)

  placemarkElement = kmlDoc.createElement('Placemark')
  
  descriptionElement = kmlDoc.createElement('description')
  descriptionText = kmlDoc.createTextNode(address)
  descriptionElement.appendChild(descriptionText)
  placemarkElement.appendChild(descriptionElement)
  pointElement = kmlDoc.createElement('Point')
  placemarkElement.appendChild(pointElement)
  coorElement = kmlDoc.createElement('coordinates')

  # This geocodes the address and adds it to a  element.
  coordinates = geocode(address)
  coorElement.appendChild(kmlDoc.createTextNode(coordinates))
  pointElement.appendChild(coorElement)

  documentElement.appendChild(placemarkElement)

  # This writes the KML Document to a file.
  kmlFile = open(fileName, 'w')
  kmlFile.write(kmlDoc.toprettyxml(' '))  
  kmlFile.close()

if __name__ == '__main__':
  createKML('1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA', 'google.kml')

其他注意事項

計時地理編碼要求

地理編碼要求將取決於地理編碼器的每日查詢上限。如要進一步瞭解這些限制,請參閱 Google Geocoding API 說明文件。為避免傳送查詢的速度過快至地理編碼器,您可以指定每個地理編碼要求之間的延遲時間。每次收到 OVER_QUERY_LIMIT 狀態時,您都可以增加此延遲時間,並使用 while 迴圈,以確保在疊代到下一個地址之前,已成功完成地址的地理編碼。

變更基準國家

地理編碼器經過編碼後,會根據原始網域調整結果。 舉例來說,在 maps.google.com 的搜尋框中輸入「syracuse」,即可在「Syracuse, NY」中為城市進行地理編碼,而在 maps.google.it (義大利網域) 輸入相同的查詢,就可以找到西西里市的「Siracusa」城市。透過 HTTP 地理編碼將查詢傳送至 maps.google.it,而非 maps.google.com,這樣就能取得相同的結果,只要修改上述程式碼範例中的 mapsUrl 變數即可。如要進一步瞭解區域自訂調整,請參閱 Geocoding API 說明文件。

注意:您無法將要求傳送至不存在的 maps.google.* 伺服器,因此請務必先將國家/地區網域存在,再為您的地理編碼查詢進行重新導向。如需各國家/地區的地理編碼支援,請查看這篇文章

結語

使用上述程式碼,您現在可以使用 Python 為地址進行地理編碼,再使用其中建立 KML <Placemark> 並將其儲存到磁碟。如果您發現每天需要對更多地址進行地理編碼,因而超出上限,或是 Google 地理編碼器未涵蓋所需地區,請考慮使用其他額外的網路服務。

現在,您已經知道如何將地址進行地理編碼,請參閱在 Google Mashup Editor 中使用 KML使用 PHP 和 MySQL 建立 KML 一文。如果您在教學課程中有任何疑問或有任何疑問,請前往 Stack Overflow 論壇張貼問題。