Conversione di file CSV in KML

Mano Marks, team delle API di Google Geo
marzo 2008

Obiettivo

Questo tutorial illustra le nozioni di base su come creare dati KML da dati CSV (valori separati da virgole) utilizzando Python. I dati CSV sono uno dei formati di file più diffusi attualmente in uso. La maggior parte dei fogli di lavoro e dei database consente sia di leggere che di scrivere file CSV. Il suo formato semplice può essere modificato in un editor di testo. Molti linguaggi di programmazione, come Python, hanno librerie speciali per leggere e scrivere file CSV. È quindi un ottimo mezzo per scambiare grandi quantità di dati.

Anche se gli esempi di codice di questo tutorial sono in Python, possono essere adattati alla maggior parte degli altri linguaggi di programmazione. Questo tutorial utilizza il codice degli indirizzi di geocodifica per l'utilizzo in KML per trasformare un indirizzo in coordinate di longitudine e latitudine. Inoltre, utilizza il nuovo elemento <ExtendedData> di KML 2.2 e sfrutta la creazione di modelli dei fumetti descritto in Aggiunta di dati personalizzati. Di conseguenza, il file KML prodotto non è attualmente supportato in Google Maps o in altre applicazioni che utilizzano KML, ma il codice può essere adattato per produrre KML compatibile con Maps.

Dati di esempio

Per questo tutorial, utilizza il file google-addresses.csv come file CSV di esempio. Questo file contiene tutti gli indirizzi, i numeri di telefono e i numeri di fax dei vari uffici Google negli Stati Uniti. Di seguito è riportato il testo del file:

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,

Come puoi notare, ogni riga è una serie di stringhe di testo separate da virgole. Ogni virgola delimita un campo; ogni riga ha lo stesso numero di virgole. La prima riga contiene i nomi dei campi in ordine. Ad esempio, il primo blocco di testo in ogni riga è il campo "Office", il secondo "Indirizzo1" e così via, Python può trasformarlo in una raccolta di dicts chiamato DictReader che ti consente di esaminare ogni riga. Questo esempio di codice si basa sulla conoscenza prima della struttura dei dati, ma puoi aggiungere alcuni gestori di base per trasferire la struttura dei campi in modo dinamico.

Analisi del file CSV

Il modulo xml.dom.minidom di Python offre ottimi strumenti per la creazione di documenti XML e, poiché KML è XML, lo utilizzerai molto in questo tutorial. Crei un elemento con createElement o createElementNS e lo aggiungi a un altro elemento con appendChild. Questi sono i passaggi per analizzare il file CSV e creare un file KML.

  1. Importa geocoding_for_kb.py nel modulo.
  2. Crea un DictReader per i file CSV. DictReader è una raccolta di dicts, una per ogni riga.
  3. Crea il documento utilizzando l'xml.dom.minidom.Document() di Python.
  4. Crea l'elemento principale <kml> utilizzando createElementNS.
  5. Aggiungilo al documento.
  6. Crea un elemento <Document> utilizzando createElement.
  7. Aggiungilo all'elemento <kml> utilizzando appendChild.
  8. Per ogni riga, crea un elemento <Placemark> e aggiungilo all'elemento <Document>.
  9. Per ogni colonna in ogni riga, crea un elemento <ExtendedData> e aggiungilo all'elemento <Placemark> che hai creato nel passaggio 8.
  10. Crea un elemento <Data> e aggiungilo all'elemento <ExtendedData>. Assegna all'elemento <Data> un attributo name e assegnagli il valore del nome colonna utilizzando setAttribute.
  11. Crea un elemento <value> e aggiungilo all'elemento <Data>. Crea un nodo di testo e assegnagli il valore della colonna utilizzando createTextNode. Aggiungi il nodo di testo all'elemento <value>.
  12. Crea un elemento <Point> e aggiungilo all'elemento <Placemark>. Crea un elemento <coordinates> e aggiungilo all'elemento <Point>.
  13. Estrai l'indirizzo dalla riga in modo che sia una singola stringa in questo formato: Indirizzo1,Indirizzo2,Città,Stato,Zip. Quindi la prima riga sarà 1600 Amphitheater Parkway,,Mountain View,CA,94043. È consentito utilizzare virgole uno accanto all'altro. Tieni presente che per eseguire questa operazione sono necessarie le conoscenze preliminari sulla struttura del file CSV e sulle colonne che costituiscono l'indirizzo.
  14. Utilizza la geocodifica dell'indirizzo tramite il codice geocoding_for_kb.py, come spiegato nella sezione Indirizzi di geocodifica per l'utilizzo in KML. Restituisce una stringa che corrisponde alla longitudine e alla latitudine della posizione.
  15. Crea un nodo di testo e assegnagli il valore delle coordinate indicate nel passaggio 14, quindi aggiungilo all'elemento <coordinates>.
  16. Scrivi il documento KML in un file.
  17. Se trasmetti un elenco di nomi di colonne come argomenti allo script, lo script aggiungerà gli elementi in questo ordine. Se non ci interessasse l'ordine degli elementi, potremmo utilizzare dict.keys() per produrre un list. Tuttavia, dict.keys() non conserva l'ordine originale dal documento. Per utilizzare questo argomento, trasmetti nell'elenco dei nomi dei campi come elenco separato da virgole, in questo modo:
    python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax

Codice Python di esempio

Di seguito è mostrato un codice campione per creare un file KML da un file CSV utilizzando Python 2.2. Puoi anche scaricarlo qui.


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

Esempio di KML creato

Di seguito è riportato un esempio del file KML creato da questo script. Nota come alcuni<value> elementi hanno solo spazi vuoti al loro interno. Questo perché il campo non conteneva nessun dato. Puoi anche scaricare l'esempio completo qui.

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

Di seguito è riportato uno screenshot di come verrà visualizzato il file KML in Google Earth. Poiché<Placemark> ogni elemento non ha <BalloonStyle><text> e nessun elemento <description>, il fumetto utilizza per impostazione predefinita uno stile tabella, disegnando gli elementi <Data>.

Screenshot del file KML creato da questo script

Considerazione della geocodifica

come menzionato in "Indirizzi di geocodifica per l'uso in KML", ma vale la pena ripeterlo. Le richieste di geocodifica saranno soggette alla frequenza di query massima del geocodificatore e a 15.000 query al giorno in base al tuo IP. Inoltre, un codice di stato restituisce un codice di stato 620 se esegui query più rapidamente di quanto possa gestire. Un elenco completo dei codici di stato è disponibile qui. Per assicurarti di non inviare query troppo rapidamente al geocodificatore, puoi specificare un ritardo tra ogni richiesta di geocodifica. Puoi aumentare questo ritardo ogni volta che ricevi uno stato 620 e utilizzare un loop while per assicurarti di avere geocodificato correttamente un indirizzo prima di passare a quello successivo. Ciò significa che se il tuo file CSV è molto grande, potresti dover modificare il codice di geocodifica o tenere traccia della velocità con cui stai creando i segnaposto e rallentarlo se procedi troppo velocemente.

Conclusione

Ora puoi usare Python per creare un file KML a partire da un file CSV. Utilizzando il codice fornito, il file KML funziona solo in Google Earth. Puoi modificarla affinché funzioni sia in Maps che in Earth utilizzando <description> invece di <ExtendedData>. È anche facile convertire questo esempio di codice in qualsiasi altro linguaggio di programmazione che fornisce XML.

Ora che hai completato la conversione di tutti i file CSV in formato KML, puoi consultare altri articoli KML, ad esempio Utilizzo di PHP e MySQL per la creazione di file KML e l'articolo della Guida per gli sviluppatori di Google su ExtendedData, Aggiunta di dati personalizzati.

Torna all'inizio