KML 用住所のジオコーディング

Google Geo チーム Mano Marks
作成: 2007 年 12 月
更新日: 2013 年 12 月

目的

このチュートリアルは、スクリプト言語に精通し、Google Geocoding API を使って住所をジオコーディングして KML ファイルに組み込むデベロッパーを対象としています。コードサンプルは Python で記述されていますが、他のほとんどのプログラミング言語にも簡単に適用できます。

ジオコーディングとは、住所を緯度と経度の座標のセットに変換し、地図上に住所を示す処理です。住所をジオコーディングして KML ファイルに直接配置することもできます。これは、フォームにデータが入力され、リクエストに応じて KML ファイルを生成する場合などに一般的です。これらの KML ファイルはデータベースやファイル システムに保存することも、ファイルに接続する NetworkLink に返すこともできます。なお、この方法を使用するときは、Geocoding API の利用規約を遵守する必要があります。これは、結果を保存できます。また、1 日にジオコーディングできる要素の数にも制限があります。

このチュートリアルでは、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 の minidom は DOM の実装であり、DOM はほとんどのプログラミング言語でサポートされているため、このプロセスは簡単に他のプログラミング言語に移植できます。手順は次のとおりです。

  1. Python の xml.dom.minidom.Document() を使用してドキュメントを作成します。
  2. createElementNS. を使用してルート <kml> 要素を作成する
  3. appendChild を使用してドキュメントに追加します。
  4. createElement を使用してドキュメント要素を作成します。
  5. appendChild を使用して、<kml> 要素に追加します。
  6. アドレスごとに、createElement を使用して <Placemark> 要素を作成し、Document 要素に追加します。次に、<description> 要素を作成して住所の値を割り当て、<Placemark> 要素に追加します。
  7. <Point> 要素を作成し、子 <coordinates> 要素を追加して、<Placemark> 要素に追加します。
  8. 住所を Maps API Geocoder に送信します。これにより、レスポンスが 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')

その他の考慮事項

ジオコード化リクエストのタイミング

ジオコーディング リクエストには、ジオコーダの最大 1 日あたりのクエリ レート上限が適用されます。これらの制限の詳細については、Google Geocoding API のドキュメントをご覧ください。ジオコーダにクエリを速く送信しすぎないように、ジオコーダ リクエスト間の遅延を指定できます。この遅延は、OVER_QUERY_LIMIT ステータスを受け取るたびに増やすことができます。また、while ループを使用して、住所をジオコーディングしたことにより次の住所に反復処理が行われるようにします。

拠点国を変更する

ジオコーダは、元のドメインに応じて検索結果がバイアスされるようにプログラムされています。 たとえば、maps.google.com の検索ボックスに「syracuse」と入力すると、「Syracuse, NY」という都市がジオコーディングされますが、maps.google.it(イタリアのドメイン)では同じクエリを入力すると、シチリア島の「シラクーザ」市が表示されます。このクエリは、HTTP ジオコーディングを介して maps.google.commaps.google.it に送信することで同じ結果が得られます。これは、上記のサンプルコードの mapsUrl 変数を変更することで実施できます。地域バイアスの詳細については、Geocoding API のドキュメントをご覧ください。

注: 存在しない Maps.google.* サーバーにリクエストを送信することはできないため、ジオコーディング クエリをリダイレクトする前に国のドメインが存在することを確認してください。国別のジオコードのサポートについては、この投稿をご覧ください。

まとめ

上記のコードを使用して、Python で住所をジオコーディングし、<Placemark> から KML を作成してディスクに保存できるようになりました。1 日の上限数を超える住所をジオコーディングする必要があるか、Google ジオコーダが関心のある地域に対応していない場合は、追加のジオコーディング ウェブサービスの使用を検討してください。

ここでは住所のジオコーディングの方法を確認しました。次に、Google Mashup Editor で KML を使用するPHP と MySQL を使用して KML を作成するをご覧ください。このチュートリアルに問題がある場合や質問がある場合は、Stack Overflow フォーラムに投稿してください。