Mã hoá địa lý cho địa chỉ để sử dụng trong KML

Mano Marks, Nhóm Google Geo
Tác giả: Tháng 12 năm 2007
Cập nhật: Tháng 12 năm 2013

Mục tiêu

Hướng dẫn này dành cho những nhà phát triển đã quen thuộc với các ngôn ngữ kịch bản và muốn tìm hiểu cách sử dụng Google Geocoding API để mã hoá địa lý các địa chỉ và kết hợp chúng vào một tệp KML. Mặc dù các mẫu mã được trình bày bằng Python, nhưng bạn có thể dễ dàng điều chỉnh chúng cho phù hợp với hầu hết các ngôn ngữ lập trình khác.

Mã hoá địa lý là quá trình chuyển đổi một địa chỉ thành một tập hợp các toạ độ vĩ độ/kinh độ, giúp bạn có thể cho biết địa chỉ trên bản đồ. Bạn có thể muốn mã hoá địa lý các địa chỉ và đưa trực tiếp vào một tệp KML. Ví dụ: điều này thường xảy ra khi dữ liệu đang được nhập vào biểu mẫu và bạn đang tạo tệp KML để phản hồi các yêu cầu. Các tệp KML này có thể được lưu trữ trong cơ sở dữ liệu, trong hệ thống tệp hoặc được trả về NetworkLink kết nối với tệp của bạn. Xin lưu ý rằng khi sử dụng kỹ thuật này, bạn phải tuân thủ Điều khoản dịch vụ của Geocoding API vì có một số hạn chế về thời gian bạn có thể lưu trữ kết quả, cũng như số lượng phần tử bạn có thể mã hoá địa lý mỗi ngày.

Hướng dẫn này cho bạn biết cách dùng Python để lấy chuỗi "1600 Amphitheatre Pkwy, Mountain View, CA 94043" và chuyển thành chuỗi sau:

<?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>

Tạo một tài liệu KML

KML là một ngôn ngữ đánh dấu XML, vì vậy, chúng ta có thể sử dụng các hàm xml.dom.minidom tích hợp của Python để tạo một tài liệu KML. Minidom của Python là một cách triển khai DOM và DOM được hỗ trợ trong hầu hết các ngôn ngữ lập trình, vì vậy, quá trình này sẽ dễ dàng chuyển sang một ngôn ngữ lập trình khác. Sau đây là các bước:

  1. Tạo tài liệu bằng xml.dom.minidom.Document() của Python.
  2. Tạo phần tử <kml> gốc bằng cách sử dụng createElementNS.
  3. Nối đối tượng này vào tài liệu bằng cách sử dụng appendChild.
  4. Tạo một phần tử Tài liệu bằng createElement.
  5. Nối phần tử này vào phần tử <kml> bằng appendChild.
  6. Đối với mỗi địa chỉ, hãy tạo một phần tử <Placemark> bằng createElement và nối phần tử đó vào phần tử Document. Sau đó, hãy tạo một phần tử <description>, chỉ định giá trị của địa chỉ cho phần tử đó và nối phần tử đó vào phần tử <Placemark>.
  7. Tạo một phần tử <Point>, thêm một phần tử con <coordinates> và nối phần tử đó vào phần tử <Placemark>.
  8. Gửi địa chỉ đến Bộ mã hoá địa lý của Maps API. Bộ mã hoá này sẽ gửi một phản hồi ở định dạng JSON hoặc XML. Sử dụng urllib.urlopen() để truy xuất tệp và đọc tệp đó thành một chuỗi.
  9. Phân tích cú pháp phản hồi và trích xuất các phần tử kinh độ và vĩ độ.
  10. Tạo một nút văn bản trong phần tử <coordinates> và chỉ định chuỗi kinh độ/vĩ độ làm giá trị của nút đó.
  11. Ghi tài liệu KML vào một tệp văn bản.

Mã Python mẫu

Xin lưu ý rằng mã mẫu bên dưới sử dụng một biến mapsKey giả. Bạn cần thay thế khoá này bằng khoá riêng của mình.

Dưới đây là mã mẫu để mã hoá địa lý bằng Python 2.7 và đầu ra 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')

Những yếu tố khác cần cân nhắc

Định thời gian cho các yêu cầu mã hoá địa lý

Các yêu cầu mã hoá địa lý sẽ tuân theo giới hạn tối đa về tốc độ truy vấn hằng ngày của bộ mã hoá địa lý. Vui lòng tham khảo tài liệu về Google Geocoding API để biết thêm thông tin về các giới hạn này. Để đảm bảo bạn không gửi truy vấn quá nhanh đến trình mã hoá địa lý, bạn có thể chỉ định độ trễ giữa mỗi yêu cầu mã hoá địa lý. Bạn có thể tăng độ trễ này mỗi khi nhận được trạng thái OVER_QUERY_LIMIT và sử dụng vòng lặp while để đảm bảo bạn đã mã hoá địa lý thành công một địa chỉ trước khi lặp lại địa chỉ tiếp theo.

Thay đổi quốc gia cơ sở

Trình mã hoá địa lý được lập trình để thiên vị kết quả tuỳ thuộc vào miền xuất phát. Ví dụ: khi bạn nhập "syracuse" vào hộp tìm kiếm trên maps.google.com, hệ thống sẽ mã hoá địa lý thành phố "Syracuse, NY", trong khi nếu bạn nhập cùng cụm từ tìm kiếm đó trên maps.google.it (miền của Ý), hệ thống sẽ tìm thấy thành phố "Siracusa" ở Sicily. Bạn sẽ nhận được kết quả tương tự bằng cách gửi truy vấn đó thông qua tính năng mã hoá địa lý HTTP đến maps.google.it thay vì maps.google.com. Bạn có thể thực hiện việc này bằng cách sửa đổi biến mapsUrl trong mã mẫu ở trên. Tham khảo tài liệu về Geocoding API để biết thêm thông tin về Thiên vị theo khu vực.

Lưu ý: Bạn không thể gửi yêu cầu đến một máy chủ maps.google.* không tồn tại, vì vậy, hãy đảm bảo rằng có một miền quốc gia trước khi chuyển hướng các truy vấn mã hoá địa lý đến miền đó. Để biết thông tin hỗ trợ mã địa lý theo quốc gia, hãy xem bài đăng này.

Kết luận

Bằng cách sử dụng đoạn mã ở trên, giờ đây, bạn có thể mã hoá địa lý một địa chỉ bằng Python, tạo <Placemark> KML từ địa chỉ đó và lưu vào đĩa. Nếu bạn nhận thấy mình cần mã hoá địa lý nhiều địa chỉ hơn mỗi ngày so với giới hạn cho phép hoặc trình mã hoá địa lý của Google không bao gồm những khu vực mà bạn quan tâm, hãy cân nhắc sử dụng các dịch vụ web mã hoá địa lý bổ sung.

Giờ bạn đã biết cách mã hoá địa lý địa chỉ của mình, hãy xem các bài viết về Sử dụng KML trong Google Mashup EditorSử dụng PHP và MySQL để tạo KML. Nếu bạn gặp vấn đề hoặc có thắc mắc về hướng dẫn này, vui lòng đăng trong diễn đàn Stack Overflow.