Tháng 3 năm 2008
Mục tiêu
Phần hướng dẫn này trình bày những thông tin cơ bản về cách tạo tệp 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 được sử dụng hiện nay. Hầu hết 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 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 lượng lớn dữ liệu.
Mặc dù mã mẫu trong hướng dẫn này được viết bằng Python, nhưng bạn có thể điều chỉnh các mã đó cho hầu hết ngôn ngữ lập trình khác. Hướng dẫn này dùng mã từ Mã hoá địa lý
để sử dụng trong KML để biến
địa chỉ thành kinh độ/vĩ độ. Nó 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 trong phần Thêm
dữ liệu tùy chỉnh. Do đó, KML được tạo hiện không được hỗ trợ trong Google Maps hoặc các ứng dụng tiêu thụ KML khác, nhưng bạn có thể điều chỉnh mã này để tạo KML tương thích với Maps.
Dữ liệu mẫu
Để xem hướng dẫn này, hãy sử dụng tệp google-Address.csv dưới dạng 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 nhiều văn phòng Google tại Hoa Kỳ. Dưới đây là nội dung văn bản 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ố dấu phẩy.
Dòng đầu tiên chứa tên của các trường theo thứ tự. Chẳng hạn, khối văn bản đầu tiên trong mỗi hàng là trường "Office", văn bản thứ hai "Address1", v.v. Python có thể biến trường đó thành một tập hợp dicts
được gọi là DictReader
, cho phép bạn đi qua từng hàng. Mã mẫu này dựa trên 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 để tự động truyền cấu trúc trườ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 nó khá nhiều trong hướng dẫn này. Bạn tạo một phần tử có createElement
hoặc createElementNS
và thêm vào một phần tử khác có 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 Geocodes_for_{8/}.py vào mô-đun của bạn.
- Tạo
DictReader
cho các tệp CSV.DictReader
là một tập hợpdicts
, mỗi tập hợp mỗi hàng. - Tạo tài liệu bằng cách sử dụng
xml.dom.minidom.Document()
của Python. - Tạo phần tử
<kml>
gốc bằng cách sử dụngcreateElementNS.
- Thêm vào tài liệu
.
- Tạo phần tử
<Document>
bằng cách sử dụngcreateElement
. - Thêm nó vào phần tử
<kml>
bằng cách sử dụngappendChild
. - Đối với mỗi hàng, hãy tạo một phần tử
<Placemark>
và thêm 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à thêm phần tử đó vào phần tử<Placemark>
đã tạo ở bước 8. - Tạo một phần tử
<Data>
rồi thêm phần tử đó vào phần tử<ExtendedData>
. Đặt phần tử tên cho phần tử<Data>
và gán giá trị của tên cột đó bằngsetAttribute
. - Tạo một phần tử
<value>
và thêm 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 thêm phần tử đó vào phần tử<Placemark>
. Tạo một phần tử<coordinates>
rồi thêm phần tử đó vào phần tử<Point>
. - Trích xuất địa chỉ từ hàng để trở thành một
chuỗi duy nhất ở định dạng
này: Address1,Address2,City,State,Zip. Vì vậy, hàng đầu tiên
sẽ là
1600 Amphitheater Parkway,,Mountain View,CA,94043
. Chấp nhận có dấu phẩy bên cạnh nhau. Lưu ý: Để làm được điều này, bạn cần phải có kiến thức trước về cấu trúc của tệp CSV và những cột nào cấu thành địa chỉ. - Mã hóa địa lý địa chỉ bằng cách sử dụng mã geo quá_mã_cho_mã_web_của_chúng tôi. được giải thích trong phần Địa chỉ mã hoá địa lý để sử dụng trong KML. Phương thứ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
toạ độ trong bước 14, sau đó thêm nút đó vào phần tử
<coordinates>
. - Ghi tài liệu KML vào 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, 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 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ư trong ví dụ 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 trình bày dưới đây. 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 KML mẫu
Dưới đây là ví dụ về tệp KML mà tập lệnh này tạo ra.
Hãy lưu ý cách một số<value>
phần tử chỉ có khoảng trắng trong đó. Nguyên nhân là do trường này không có dữ liệu nào. 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>
...
Ảnh chụp màn hình
Dưới đây là ảnh chụp màn hình của tệp KML trong Google Earth.
Do mỗi phần tử<Placemark>
không có phần tử <BalloonStyle><text>
và không có phần tử <description>
, nên hộp chú giải mặc định là kiểu bảng, vẽ trên các phần tử <Data>
.
Cân nhắc về việc mã hóa địa lý
Điều này đã được đề cập trong "Địa chỉ mã hóa địa lý để sử dụng trong KML",
nhưng nó lặp lại. Các yêu cầu mã hóa địa lý của bạn sẽ phải tuân theo tỷ lệ truy vấn tối đa của bộ mã hóa 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á sẽ trả về mã trạng thái 620
nếu bạn truy vấn mã này nhanh hơn tốc độ xử 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 bộ 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ã hóa thành công một địa chỉ trước khi lặp lại vào địa chỉ tiếp theo. Điều này có nghĩa là nếu tệp CSV của bạn rất lớn, bạn có thể phải sửa đổi mã mã hoá địa lý hoặc theo dõi tốc độ tạo dấu vị trí và giảm tốc độ đó nếu chạy quá nhanh.
Kết luận
Giờ đây, bạn có thể sử dụng Python để tạo tệp KML từ tệp CSV. Sử 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 để làm việc trong cả Maps và Earth bằng cách sử dụng
<description>
thay vì <ExtendedData>
.
Bạn cũng có thể dễ dàng chuyển đổi mã mẫu này sang ngôn ngữ lập trình khác có hỗ trợ XML.
Sau khi chuyển đổi xong tất cả các tệp CSV sang KML, bạn có thể xem các bài viết KML khác, chẳng hạn như Sử dụng PHP và MySQL để tạo KML và bài viết Hướng dẫn cho nhà phát triển trên ExtendedData, Thêm dữ liệu tuỳ chỉnh.