CSV-Dateien in KML konvertieren

Mano Marks, Google Geo APIs-Team
März 2008

Ziel

In dieser Anleitung werden die Grundlagen zum Erstellen von KML-Daten aus kommagetrennten Werten (CSV) mit Python beschrieben. CSV-Daten sind eines der am häufigsten verwendeten Dateiformate. Die meisten Tabellen und Datenbanken können CSV-Dateien lesen und schreiben. Das einfache Format lässt sich in einem Texteditor bearbeiten. Viele Programmiersprachen wie Python haben spezielle Bibliotheken zum Lesen und Schreiben von CSV-Dateien. Daher eignet sie sich hervorragend für den Austausch großer Datenmengen.

Die Codebeispiele in dieser Anleitung sind in Python verfügbar, können aber an die meisten anderen Programmiersprachen angepasst werden. In dieser Anleitung wird Code aus Geocoding Addresss for Use in KML verwendet, um Adressen in Längen- und Breitengradkoordinaten umzuwandeln. Außerdem wird das neue <ExtendedData>-Element von KML 2.2 verwendet und die Info-Pop-up-Vorlagen, wie unter Benutzerdefinierte Daten hinzufügen beschrieben, genutzt. Deshalb wird die erstellte KML-Datei derzeit in Google Maps oder anderen Anwendungen, die KML verwenden, nicht unterstützt. Der Code kann jedoch angepasst werden, um mit Google Maps kompatible KMLs zu erstellen.

Beispieldaten

Verwenden Sie für diese Anleitung die Datei google-address.csv als CSV-Beispieldatei. Diese Datei enthält alle Adressen, Telefonnummern und Faxnummern der verschiedenen Google-Niederlassungen in den USA. Hier der Text der Datei:

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,

Beachten Sie, dass jede Zeile aus einer Reihe von Textstrings besteht, die durch Kommas getrennt sind. Jedes Komma trennt ein Feld. Jede Zeile hat die gleiche Anzahl von Kommas. Die erste Zeile enthält die Namen der Felder in der richtigen Reihenfolge. Der erste Textblock in jeder Zeile ist beispielsweise das Feld „Office“ und der zweite „Address1“. Python kann dies in eine Sammlung von dicts namens DictReader umwandeln, mit der Sie die einzelnen Zeilen durchlaufen können. Dieses Codebeispiel setzt voraus, dass Sie die Struktur Ihrer Daten vorher kennen. Sie könnten jedoch einige grundlegende Handler hinzufügen, um die Feldstruktur dynamisch zu übergeben.

CSV-Datei parsen

Das Modul xml.dom.minidom von Python bietet hervorragende Tools zum Erstellen von XML-Dokumenten. Da KML XML ist, werden Sie es in dieser Anleitung ziemlich stark verwenden. Sie erstellen ein Element mit createElement oder createElementNS und fügen es mit appendChild an ein anderes Element an. Dies sind die Schritte zum Parsen der CSV-Datei und Erstellen einer KML-Datei.

  1. Importieren Sie Geocodierung_für_KML.py in Ihr Modul.
  2. Erstellen Sie einen DictReader für die CSV-Dateien. DictReader ist eine Sammlung von dicts, eine für jede Zeile.
  3. Erstellen Sie das Dokument mit xml.dom.minidom.Document() von Python.
  4. Erstellen Sie das Stammelement <kml> mit createElementNS.
  5. Hängen Sie es an das Dokument an.
  6. Erstellen Sie mit createElement ein <Document>-Element.
  7. Hängen Sie es mithilfe von appendChild an das Element <kml> an.
  8. Erstellen Sie für jede Zeile ein <Placemark>-Element und hängen Sie es an das <Document>-Element an.
  9. Erstellen Sie für jede Spalte in jeder Zeile ein <ExtendedData>-Element und hängen Sie es an das Element <Placemark> an, das Sie in Schritt 8 erstellt haben.
  10. Erstellen Sie ein <Data>-Element und hängen Sie es an das <ExtendedData>-Element an. Weisen Sie dem Element <Data> ein Attribut zu und weisen Sie ihm mit setAttribute den Wert des Spaltennamens zu.
  11. Erstellen Sie ein <value>-Element und hängen Sie es an das Element <Data> an. Erstellen Sie einen Textknoten und weisen Sie ihm den Wert der Spalte mit createTextNode zu. Hängen Sie den Textknoten an das Element <value> an.
  12. Erstellen Sie ein <Point>-Element und hängen Sie es an das <Placemark>-Element an. Erstellen Sie ein <coordinates>-Element und hängen Sie es an das <Point>-Element an.
  13. Extrahieren Sie die Adresse aus der Zeile, sodass sie ein einzelner String in diesem Format ist: Address1,Address2,City,State,Zip. Die erste Zeile wäre also 1600 Amphitheater Parkway,,Mountain View,CA,94043. Es ist kein Problem, wenn ein Komma nebeneinander steht. Dazu müssen Sie die Struktur der CSV-Datei kennen und wissen, welche Spalten die Adresse darstellen.
  14. Geocodieren Sie die Adresse mithilfe des Geocoding_for_kml.py-Codes, wie unter Geocoding-Adressen zur Verwendung in KML erläutert. Dadurch wird ein String mit Längen- und Breitengrad des Standorts zurückgegeben.
  15. Erstellen Sie einen Textknoten und weisen Sie ihm den Wert der Koordinaten in Schritt 14 zu. Anschließend hängen Sie ihn an das Element <coordinates> an.
  16. Schreiben Sie das KML-Dokument in eine Datei.
  17. Wenn Sie eine Liste von Spaltennamen als Argumente an das Skript übergeben, fügt das Skript Elemente in dieser Reihenfolge hinzu. Wenn uns die Reihenfolge der Elemente nicht wichtig ist, könnten wir dict.keys() verwenden, um list zu erstellen. dict.keys() behält jedoch nicht die ursprüngliche Reihenfolge des Dokuments bei. Wenn Sie dieses Argument verwenden möchten, übergeben Sie die Liste mit den Feldnamen als kommagetrennte Liste. Beispiel:
    python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax

Python-Beispielcode

Im Folgenden sehen Sie Beispielcode zum Erstellen einer KML-Datei aus einer CSV-Datei mit Python 2.2. Sie können sie auch hier herunterladen.


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 a  element 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()

Beispiel-KML-Datei erstellt

Unten sehen Sie ein Beispiel für die von diesem Skript erstellte KML-Datei. Wie Sie sehen, enthalten einige<value> Elemente nur Leerzeichen. Das liegt daran, dass das Feld keine Daten enthielt. Sie können auch das vollständige Beispiel herunterladen.

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

Screen shot

Im Folgenden sehen Sie einen Screenshot der KML-Datei in Google Earth. Da jedes<Placemark>-Element kein <BalloonStyle><text>- und kein <description>-Element hat, wird im Info-Pop-up standardmäßig ein Tabellenstil verwendet, der auf den <Data>-Elementen basiert.

Von diesem Skript erstellte KML-Datei

Überlegungen zur Geocodierung

Dies wurde bereits in „Geocoding Adressen für die Verwendung in KML“ erwähnt, aber er wird wiederholt. Für Ihre Geocoding-Anfragen gilt die maximale Abfragerate von 15.000 Abfragen pro Tag basierend auf Ihrer IP-Adresse. Darüber hinaus wird vom Geocoder der Statuscode 620 zurückgegeben, wenn Sie ihn schneller abfragen, als er verarbeiten kann. Eine vollständige Liste der Statuscodes finden Sie hier. Damit Abfragen nicht zu schnell an den Geocoder gesendet werden, können Sie zwischen den einzelnen Geocode-Anfragen eine Verzögerung angeben. Sie können diese Verzögerung bei jedem 620-Status erhöhen und mithilfe einer while-Schleife sicherstellen, dass eine Adresse erfolgreich geocodiert wurde, bevor sie zur nächsten iteriert. Wenn Ihre CSV-Datei sehr groß ist, müssen Sie daher möglicherweise den Geocoding-Code ändern oder die Geschwindigkeit der Erstellung von Ortsmarkierungen verfolgen und diesen Vorgang verlangsamen, wenn Sie zu schnell arbeiten.

Fazit

Jetzt können Sie mit KML eine KML-Datei aus einer CSV-Datei erstellen. Mit dem bereitgestellten Code funktioniert die KML-Datei nur in Google Earth. Sie können ihn so ändern, dass er sowohl in Google Maps als auch in Google Earth funktioniert. Verwenden Sie dazu <description> anstelle von <ExtendedData>. Außerdem lässt sich dieses Codebeispiel problemlos in andere Programmiersprachen umwandeln, die XML-Unterstützung bieten.

Nachdem Sie nun alle Ihre CSV-Dateien in KML konvertiert haben, sollten Sie sich die weiteren KML-Artikel ansehen, z. B. KML mit MySQL erstellen und den Google-Entwicklerleitfaden zu erweiterten Daten.

Nach oben