Marzec 2008
Cel
Ten samouczek opisuje podstawy tworzenia pliku KML na podstawie danych wartości rozdzielanych przecinkami (CSV) przy użyciu języka Python. Pliki CSV to jeden z najpopularniejszych obecnie formatów plików. Większość arkuszy kalkulacyjnych i baz danych może odczytywać i zapisywać pliki CSV. Prosty format można edytować w edytorze tekstu. Wiele języków programowania, takich jak Python, ma specjalne biblioteki do odczytu i zapisu plików CSV. To świetna okazja do wymiany dużych ilości danych.
Przykładowy kod w tym samouczku jest w Pythonie, ale można go dostosować do większości języków programowania. W tym samouczku używamy kodu z adresów geograficznych do użycia w plikach KML, aby przekształcić adres we współrzędne długości i szerokości geograficznej. Wykorzystuje też nowy element <ExtendedData>
języka KML 2.2 i używa szablonów dymków opisanych w artykule Dodawanie danych niestandardowych. W związku z tym wygenerowany plik KML nie jest obecnie obsługiwany w Mapach Google ani w innych aplikacjach obsługujących KML, ale można dostosować kod, aby utworzyć plik KML zgodny z Mapami.
Przykładowe dane
W tym samouczku użyj pliku google-addresses.csv jako przykładowego pliku CSV. Ten plik zawiera wszystkie adresy, numery telefonów i numery faksów różnych biur Google w Stanach Zjednoczonych. Oto tekst pliku:
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,
Zwróć uwagę, że każdy wiersz jest ciągiem ciągów tekstowych rozdzielonych przecinkami.
Każdy przecinek oddziela pole, a wiersz zawiera taką samą liczbę przecinków.
Pierwszy wiersz zawiera nazwy pól w kolejności. Na przykład pierwszy blok tekstu w każdym wierszu to pole „Office”, drugi „Adres1” itp. Python może przekształcić ten ciąg w zbiór dicts
nazywany DictReader
, który umożliwia przejście przez każdy wiersz. Ten przykładowy kod opiera się na znajomości wcześniej struktury danych, ale można też dodać kilka podstawowych modułów obsługi, które dynamicznie przekazują strukturę pola.
Analizowanie pliku CSV
Moduł Pythona xml.dom.minidom
udostępnia doskonałe narzędzia do tworzenia dokumentów XML, a ponieważ KML jest w formacie XML, będziesz go używać w tym samouczku bardzo często. Tworzysz element za pomocą createElement
lub createElementNS
i dołączasz go do innego elementu za pomocą appendChild
.
Poniżej znajdziesz instrukcje analizowania pliku CSV i tworzenia pliku KML.
- Zaimportuj plik Geocoding_for_json.py do modułu.
- Utwórz
DictReader
w plikach CSV.DictReader
to zbiór danychdicts
, po jednym w każdym wierszu. - Utwórz dokument za pomocą
xml.dom.minidom.Document()
w Pythonie. - Utwórz główny element
<kml>
za pomocącreateElementNS.
- Dodaj go do dokumentu
.
- Utwórz element
<Document>
za pomocącreateElement
. - Dołącz go do elementu
<kml>
przy użyciuappendChild
. - Dla każdego wiersza utwórz element
<Placemark>
i dołącz go do elementu<Document>
. - Dla każdej kolumny w każdym wierszu utwórz element
<ExtendedData>
i dołącz go do elementu<Placemark>
utworzonego w kroku 8. - Utwórz element
<Data>
i dołącz go do elementu<ExtendedData>
. Nadaj elementowi<Data>
atrybut nazwy i przypisz mu wartość nazwy kolumny za pomocą atrybutusetAttribute
. - Utwórz element
<value>
i dołącz go do elementu<Data>
. Utwórz węzeł tekstowy i przypisz mu wartość kolumny za pomocącreateTextNode
. Dołącz węzeł tekstowy do elementu<value>
. - Utwórz element
<Point>
i dołącz go do elementu<Placemark>
. Utwórz element<coordinates>
i dołącz go do elementu<Point>
. - Wyodrębnij adres z wiersza, tak aby zawierał on 1 ciąg w tym formacie: Address1,Address2,City,State,Zip. Pierwszy wiersz to
1600 Amphitheater Parkway,,Mountain View,CA,94043
. Nie ma problemu, jeśli znajdują się obok nich przecinki. Aby to zrobić, musisz znać strukturę pliku CSV i dowiedzieć się, które kolumny zawierają jego adres. - Dodaj geokod z użyciem kodu geocoding_for_json.py wyjaśnionego w artykule Adresy geograficzne w pliku KML. Zwraca ciąg znaków, który zawiera długość i szerokość geograficzną lokalizacji.
- Utwórz węzeł tekstowy, przypisz mu wartość współrzędnych w kroku 14, a potem dołącz go do elementu
<coordinates>
. - Zapisz dokument KML w pliku.
- Jeśli przekażesz do skryptu listę nazw kolumn jako argumenty, skrypt doda elementy w tej kolejności. Gdybyśmy nie zajmowali się kolejnością elementów, moglibyśmy użyć właściwości
dict.keys()
, aby wygenerowaćlist
. Jednakdict.keys()
nie zachowuje oryginalnego zamówienia z dokumentu. Aby użyć tego argumentu, przekaż listę nazw pól w formie listy rozdzielonej przecinkami:python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax
Przykładowy kod w Pythonie
Przykładowy kod tworzenia pliku KML przy użyciu Pythona 2.2 znajdziesz poniżej. Możesz ją też pobrać stąd.
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()
Utworzono przykładowy plik KML
Poniżej znajdziesz przykładowy plik KML utworzony przez ten skrypt.
Zwróć uwagę, że niektóre<value>
elementy zawierają tylko spacje. Dzieje się tak, ponieważ pole
nie zawiera żadnych danych. Możesz też pobrać pełną przykład tutaj.
<?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>
...
Zrzut ekranu
Poniżej znajduje się zrzut ekranu z plikiem KML.
Każdy element <Placemark>
nie ma elementu <BalloonStyle><text>
ani elementu <description>
, dlatego dymek jest domyślnie ustawiany na styl tabeli i rysuje na elementach <Data>
.
Uwagi na temat geokodowania
Została ona wymieniona w sekcji „Adresy geograficzne do użycia w plikach KML”, ale została powtórzona. Twoje żądania geokodowania będą podlegać maksymalnej liczbie zapytań geokodera oraz 15 000 zapytań dziennie na podstawie Twojego adresu IP. Poza tym kod stanu 620
zwróci kod geokodera, jeśli podasz go szybciej niż może go obsłużyć. (Pełną listę kodów stanu znajdziesz tutaj).
Aby mieć pewność, że zapytania nie będą wysyłane zbyt szybko do geokodera, możesz określić opóźnienie między poszczególnymi żądaniami geokodowania. Możesz opóźnić to opóźnienie za każdym razem, gdy otrzymasz stan 620
, i użyć pętli while
, aby mieć pewność, że kod został prawidłowo przetworzony przed przejściem do kolejnego. Oznacza to, że jeśli plik CSV jest bardzo duży, konieczna może być zmiana kodu geograficznego lub śledzenie szybkości tworzenia oznaczeń miejsc albo spowolnienie pracy, jeśli pliki są zbyt szybkie.
Podsumowanie
Teraz możesz użyć Pythona, aby utworzyć plik KML na podstawie pliku CSV. Przy użyciu podanego kodu plik KML będzie działać tylko w Google Earth. Możesz go zmodyfikować, aby działał zarówno w Mapach, jak i w Google Earth, za pomocą <description>
zamiast <ExtendedData>
.
Możesz też łatwo przekonwertować ten przykładowy kod na dowolny inny język programowania, który obsługuje XML.
Po przekonwertowaniu wszystkich plików CSV na format KML możesz zapoznać się z innymi artykułami KML, takimi jak Używanie języka PHP i MySQL do tworzenia plików KML oraz artykułem Przewodnik Google dla programistów na temat ExtendedData, Dodawanie danych niestandardowych.