Tháng 3 năm 2008
Mục tiêu
Hướng dẫn này trình bày những kiến thức cơ bản về cách tạo KML từ dữ liệu Giá trị được phân tách bằng dấu phẩy (CSV) bằng Python. Dữ liệu CSV là một trong những định dạng tệp phổ biến nhất hiện nay. Hầu hết các bảng tính và cơ sở dữ liệu đều có thể đọc và ghi tệp CSV. Bạn có thể chỉnh sửa định dạng đơn giản của tệp này trong trình chỉnh sửa văn bản. Nhiều ngôn ngữ lập trình (chẳng hạn như Python) có các thư viện đặc biệt để đọc và ghi tệp CSV. Do đó, đây là một phương tiện tuyệt vời để trao đổi số lượng lớn dữ liệu.
Mặc dù các mẫu mã trong hướng dẫn này được viết bằng Python, nhưng bạn có thể đ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. Hướng dẫn này sử dụng mã từ Mã hoá địa lý địa chỉ để sử dụng trong KML để chuyển đổi địa chỉ thành toạ độ kinh độ/vĩ độ. Ứng dụng này cũng sử dụng phần tử <ExtendedData>
mới của KML 2.2 và tận dụng tính năng tạo mẫu bóng được nêu trong phần Thêm dữ liệu tuỳ chỉnh. Do đó, KML được tạo hiện không được hỗ trợ trong Google Maps hoặc các ứng dụng khác sử dụng KML, nhưng bạn có thể điều chỉnh mã để tạo KML tương thích với Maps.
Dữ liệu mẫu
Trong hướng dẫn này, hãy sử dụng tệp google-addresses.csv làm tệp CSV mẫu. Tệp này có tất cả địa chỉ, số điện thoại và số fax của các văn phòng Google tại Hoa Kỳ. Dưới đây là nội dung của tệp:
Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax Headquarters,1600 Amphitheatre Parkway,,,Mountain View,CA,94043,650-253-0000,650-253-0001 New York Sales & Engineering Office,76 Ninth Avenue,,,New York,NY,10011,212-565-0000,212-565-0001 Ann Arbor Sales Office,201 South Division Street,,,Ann Arbor,MI,48104,734-332-6500,734-332-6501 Atlanta Sales & Engineering Office,10 10th Street NE,,,Atlanta,GA,30309,404-487-9000,404-487-9001 Boulder Sales & Engineering Office,2590 Pearl St.,,,Boulder,CO,80302,303-245-0086,303-535-5592 Cambridge Sales & Engineering Office,5 Cambridge Center,,,Cambridge,MA,02142,617-682-3635,617-249-0199 Chicago Sales & Engineering Office,20 West Kinzie St.,,,Chicago,IL,60610,312-840-4100,312-840-4101 Coppell Sales Office,701 Canyon Drive,,,Coppell,TX,75019,214-451-4000,214-451-4001 Detroit Sales Office,114 Willits Street,,,Birmingham,MI,48009,248-351-6220,248-351-6227 Irvine Sales & Engineering Office,19540 Jamboree Road,,,Irvine,CA,92612,949-794-1600,949-794-1601 Pittsburgh Engineering Office,4720 Forbes Avenue,,,Pittsburgh,PA,15213,, Santa Monica Sales & Engineering Office,604 Arizona Avenue,,,Santa Monica,CA,90401,310-460-4000,310-309-6840 Seattle Engineering Office,720 4th Avenue,,,Kirkland,WA,98033,425-739-5600,425-739-5601 Seattle Sales Office,501 N. 34th Street,,,Seattle,WA,98103,206-876-1500,206-876-1501 Washington D.C. Public Policy Office,1001 Pennsylvania Avenue NW,,,Washington,DC,20004,202-742-6520,
Lưu ý cách mỗi dòng là một chuỗi văn bản được phân tách bằng dấu phẩy.
Mỗi dấu phẩy phân tách một trường; mỗi dòng có cùng số lượng dấu phẩy.
Dòng đầu tiên chứa tên của các trường theo thứ tự. Ví dụ: khối văn bản đầu tiên trong mỗi hàng là trường "Văn phòng", khối thứ hai là "Địa chỉ 1", v.v. Python có thể chuyển khối văn bản đó thành một tập hợp dicts
được gọi là DictReader
. Tập hợp này cho phép bạn chuyển qua từng hàng. Mẫu mã này dựa vào việc bạn biết trước cấu trúc dữ liệu của mình, nhưng bạn có thể thêm một số trình xử lý cơ bản để truyền cấu trúc trường một cách linh động.
Phân tích cú pháp tệp CSV
Mô-đun xml.dom.minidom
của Python cung cấp các công cụ tuyệt vời để tạo tài liệu XML và vì KML là XML, nên bạn sẽ sử dụng mô-đun này khá nhiều trong hướng dẫn này. Bạn tạo một phần tử bằng createElement
hoặc createElementNS
, rồi thêm vào một phần tử khác bằng appendChild
.
Sau đây là các bước để phân tích cú pháp tệp CSV và tạo tệp KML.
- Nhập geocoding_for_kml.py vào mô-đun của bạn.
- Tạo một
DictReader
cho các tệp CSV.DictReader
là một tập hợpdicts
, mỗi hàng có mộtdicts
. - Tạo tài liệu bằng
xml.dom.minidom.Document()
của Python. - Tạo phần tử
<kml>
gốc bằngcreateElementNS.
- Nối dữ liệu vào tài liệu
.
- Tạo một phần tử
<Document>
bằngcreateElement
. - Nối phần tử này vào phần tử
<kml>
bằngappendChild
. - Đối với mỗi hàng, hãy tạo một phần tử
<Placemark>
và nối phần tử đó vào phần tử<Document>
. - Đối với mỗi cột trong mỗi hàng, hãy tạo một phần tử
<ExtendedData>
và nối phần tử đó vào phần tử<Placemark>
mà bạn đã tạo ở bước 8. - Tạo một phần tử
<Data>
và nối phần tử đó vào phần tử<ExtendedData>
. Đặt cho phần tử<Data>
một thuộc tính tên và chỉ định giá trị của tên cột bằng cách sử dụngsetAttribute
. - Tạo một phần tử
<value>
rồi nối phần tử đó vào phần tử<Data>
. Tạo một nút văn bản và chỉ định giá trị của cột bằng cách sử dụngcreateTextNode
. Thêm nút văn bản vào phần tử<value>
. - Tạo một phần tử
<Point>
rồi nối phần tử đó vào phần tử<Placemark>
. Tạo một phần tử<coordinates>
và nối phần tử đó vào phần tử<Point>
. - Trích xuất địa chỉ từ hàng để địa chỉ là một chuỗi duy nhất theo định dạng sau: Địa chỉ 1,Địa chỉ 2,Thành phố,Tiểu bang,Mã bưu chính. Vậy hàng đầu tiên sẽ là
1600 Amphitheater Parkway,,Mountain View,CA,94043
. Bạn có thể đặt dấu phẩy cạnh nhau. Xin lưu ý rằng để thực hiện việc này, bạn cần có kiến thức trước về cấu trúc của tệp CSV và những cột nào tạo thành địa chỉ. - Mã hoá địa lý địa chỉ bằng mã geocoding_for_kml.py được giải thích trong phần Mã hoá địa lý địa chỉ để sử dụng trong KML. Thao tác này trả về một chuỗi là kinh độ và vĩ độ của vị trí.
- Tạo một nút văn bản và chỉ định giá trị của nút đó là giá trị của toạ độ trong bước 14, sau đó nối nút đó vào phần tử
<coordinates>
. - Ghi tài liệu KML vào một tệp.
- Nếu bạn truyền một danh sách tên cột làm đối số cho tập lệnh, thì tập lệnh sẽ thêm các phần tử theo thứ tự đó. Nếu không quan tâm đến thứ tự của các phần tử, chúng ta có thể sử dụng
dict.keys()
để tạo ra mộtlist
. Tuy nhiên,dict.keys()
không giữ nguyên thứ tự ban đầu trong tài liệu. Để sử dụng đối số này, hãy truyền vào danh sách tên trường dưới dạng danh sách được phân tách bằng dấu phẩy, như sau:python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax
Mã Python mẫu
Mã mẫu để tạo tệp KML từ tệp CSV bằng Python 2.2 được minh hoạ bên dưới. Bạn cũng có thể tải xuống tại đây.
import geocoding_for_kml
import csv
import xml.dom.minidom
import sys
def extractAddress(row):
# This extracts an address from a row and returns it as a string. This requires knowing
# ahead of time what the columns are that hold the address information.
return '%s,%s,%s,%s,%s' % (row['Address1'], row['Address2'], row['City'], row['State'], row['Zip'])
def createPlacemark(kmlDoc, row, order):
# This creates aelement for a row of data.
# A row is a dict.
placemarkElement = kmlDoc.createElement('Placemark')
extElement = kmlDoc.createElement('ExtendedData')
placemarkElement.appendChild(extElement)
# Loop through the columns and create a element for every field that has a value.
for key in order:
if row[key]:
dataElement = kmlDoc.createElement('Data')
dataElement.setAttribute('name', key)
valueElement = kmlDoc.createElement('value')
dataElement.appendChild(valueElement)
valueText = kmlDoc.createTextNode(row[key])
valueElement.appendChild(valueText)
extElement.appendChild(dataElement)
pointElement = kmlDoc.createElement('Point')
placemarkElement.appendChild(pointElement)
coordinates = geocoding_for_kml.geocode(extractAddress(row))
coorElement = kmlDoc.createElement('coordinates')
coorElement.appendChild(kmlDoc.createTextNode(coordinates))
pointElement.appendChild(coorElement)
return placemarkElement
def createKML(csvReader, fileName, order):
# This constructs the KML document from the CSV file.
kmlDoc = xml.dom.minidom.Document()
kmlElement = kmlDoc.createElementNS('http://earth.google.com/kml/2.2', 'kml')
kmlElement.setAttribute('xmlns','http://earth.google.com/kml/2.2')
kmlElement = kmlDoc.appendChild(kmlElement)
documentElement = kmlDoc.createElement('Document')
documentElement = kmlElement.appendChild(documentElement)
# Skip the header line.
csvReader.next()
for row in csvReader:
placemarkElement = createPlacemark(kmlDoc, row, order)
documentElement.appendChild(placemarkElement)
kmlFile = open(fileName, 'w')
kmlFile.write(kmlDoc.toprettyxml(' ', newl = '\n', encoding = 'utf-8'))
def main():
# This reader opens up 'google-addresses.csv', which should be replaced with your own.
# It creates a KML file called 'google.kml'.
# If an argument was passed to the script, it splits the argument on a comma
# and uses the resulting list to specify an order for when columns get added.
# Otherwise, it defaults to the order used in the sample.
if len(sys.argv) >1: order = sys.argv[1].split(',')
else: order = ['Office','Address1','Address2','Address3','City','State','Zip','Phone','Fax']
csvreader = csv.DictReader(open('google-addresses.csv'),order)
kml = createKML(csvreader, 'google-addresses.kml', order)
if __name__ == '__main__':
main()
Đã tạo tệp KML mẫu
Dưới đây là một mẫu KML mà tập lệnh này tạo ra.
Lưu ý cách một số phần tử <value>
chỉ có khoảng trắng trong đó. Đó là do trường này không có dữ liệu. Bạn cũng có thể tải toàn bộ mẫu xuống tại đây.
<?xml version="1.0" encoding="utf-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<Placemark>
<ExtendedData>
<Data name="Office">
<value>
Headquarters
</value>
</Data>
<Data name="Address1">
<value>
1600 Amphitheater Parkway
</value>
</Data>
<Data name="City">
<value>
Mountain View
</value>
</Data>
<Data name="State">
<value>
CA
</value>
</Data>
<Data name="Zip">
<value>
94043
</value>
</Data>
<Data name="Phone">
<value>
650-253-0000
</value>
</Data>
<Data name="Fax">
<value>
650-253-0001
</value>
</Data>
</ExtendedData>
<Point>
<coordinates>
-122.081783,37.423111
</coordinates>
</Point>
</Placemark>
...
Chụp ảnh màn hình
Dưới đây là ảnh chụp màn hình cho thấy tệp KML đó trông như thế nào trong Google Earth.
Vì mỗi phần tử <Placemark>
không có <BalloonStyle><text>
và không có phần tử <description>
, nên bóng mặc định là kiểu bảng, dựa trên các phần tử <Data>
.

Những điều cần cân nhắc khi mã hoá địa lý
Điều này đã được đề cập trong phần "Mã hoá địa lý địa chỉ để sử dụng trong KML", nhưng cần phải nhắc lại. Các yêu cầu mã hoá địa lý của bạn sẽ phải tuân theo tốc độ truy vấn tối đa của trình mã hoá địa lý và 15.000 truy vấn mỗi ngày dựa trên IP của bạn. Ngoài ra, bộ mã hoá địa lý sẽ trả về mã trạng thái 620
nếu bạn truy vấn nhanh hơn khả năng xử lý của bộ mã hoá địa lý. (Bạn có thể xem danh sách đầy đủ các mã trạng thái tại đâ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 620
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 đến địa chỉ tiếp theo. Điều này có nghĩa là nếu tệp CSV của bạn có kích thước rất lớn, bạn có thể phải sửa đổi mã địa lý hoặc theo dõi tốc độ tạo Điểm đánh dấu và giảm tốc độ nếu bạn đang tạo quá nhanh.
Kết luận
Giờ đây, bạn có thể dùng Python để tạo tệp KML từ tệp CSV. Khi dùng mã được cung cấp, tệp KML sẽ chỉ hoạt động trong Google Earth. Bạn có thể sửa đổi để sử dụng trong cả Maps và Earth bằng cách dùng <description>
thay vì <ExtendedData>
.
Bạn cũng có thể dễ dàng chuyển đổi mẫu mã này sang bất kỳ ngôn ngữ lập trình nào khác có hỗ trợ XML.
Giờ đây, bạn đã hoàn tất việc chuyển đổi tất cả tệp CSV sang KML, bạn có thể xem các bài viết khác về KML, chẳng hạn như Sử dụng PHP và MySQL để tạo KML và bài viết trên Hướng dẫn dành cho nhà phát triển của Google về ExtendedData, Thêm dữ liệu tuỳ chỉnh.