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 KML dai dati CSV (valori separati da virgole) utilizzando Python. I dati CSV sono uno dei formati file più diffusi in uso oggi. La maggior parte dei fogli di lavoro e dei database può leggere e 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. Pertanto, è un ottimo mezzo per lo scambio di grandi quantità di dati.

Sebbene gli esempi di codice in questo tutorial siano in Python, possono essere adattati alla maggior parte degli altri linguaggi di programmazione. Questo tutorial utilizza il codice di Geocoding Addresses for Use in KML per trasformare un indirizzo in coordinate di longitudine/latitudine. Utilizza anche il nuovo elemento <ExtendedData> di KML 2.2 e sfrutta i modelli di fumetti descritti in Aggiunta di dati personalizzati. Pertanto, il file KML prodotto non è attualmente supportato in Google Maps o in altre applicazioni che utilizzano file KML, ma il codice può essere adattato per produrre file KML compatibili 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. Ecco 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,

Nota come ogni riga sia 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 "Ufficio", il secondo "Indirizzo1" e così via. Python può trasformare questo in una raccolta di dicts chiamata DictReader che ti consente di scorrere ogni riga. Questo esempio di codice si basa sulla conoscenza preventiva della struttura dei dati, ma potresti aggiungere alcuni gestori di base per trasmettere la struttura dei campi in modo dinamico.

Analisi del file CSV

Il modulo xml.dom.minidom di Python fornisce ottimi strumenti per creare documenti XML e, poiché KML è XML, lo utilizzerai molto in questo tutorial. Crea un elemento con createElement o createElementNS e aggiungilo a un altro elemento con appendChild. Di seguito sono riportati i passaggi per analizzare il file CSV e creare un file KML.

  1. Importa geocoding_for_kml.py nel tuo modulo.
  2. Crea un DictReader per i file CSV. DictReader è una raccolta di dicts, uno per ogni riga.
  3. Crea il documento utilizzando xml.dom.minidom.Document() di Python.
  4. Crea l'elemento radice <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 di 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 di nome e assegnagli il valore del nome della 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,Codice postale. Quindi la prima riga sarebbe 1600 Amphitheater Parkway,,Mountain View,CA,94043. È normale che ci siano virgole una accanto all'altra. Tieni presente che per farlo è necessario conoscere in anticipo la struttura del file CSV e quali colonne costituiscono l'indirizzo.
  14. Geocodifica l'indirizzo utilizzando il codice geocoding_for_kml.py spiegato in Geocodifica degli indirizzi da utilizzare 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 del 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, quest'ultimo 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 del documento. Per utilizzare questo argomento, trasmetti l'elenco dei nomi dei campi come elenco separato da virgole, nel seguente modo:
    python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax

Codice Python di esempio

Di seguito è riportato un codice di esempio per la creazione di 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()

KML di esempio creato

Di seguito è riportato un esempio del file KML creato da questo script. Nota come alcuni<value> elementi contengano solo spazi bianchi. Questo perché il campo non contiene dati. 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 dell'aspetto del file KML in Google Earth. Poiché ogni elemento <Placemark> non ha <BalloonStyle><text> e nessun elemento <description>, il fumetto utilizza per impostazione predefinita uno stile di tabella, basandosi sugli elementi <Data>.

Screenshot del file KML creato da questo script

Considerazioni sulla geocodifica

Questo aspetto è stato menzionato in "Geocodifica degli indirizzi da utilizzare in KML", ma è bene ripeterlo. Le tue richieste di geocodifica saranno soggette alla frequenza massima di query del geocoder e a 15.000 query al giorno in base al tuo IP. Inoltre, il geocoder restituirà un codice di stato 620 se lo interroghi più velocemente 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 ciclo while per assicurarti di aver geocodificato correttamente un indirizzo prima di passare al successivo. Ciò significa che se il file CSV è molto grande, potresti dover modificare il codice di geocodifica o tenere traccia della velocità di creazione dei segnaposto e rallentarla se è troppo elevata.

Conclusione

Ora puoi utilizzare Python per creare un file KML da un file CSV. Utilizzando il codice fornito, il file KML funzionerà solo in Google Earth. Puoi modificarlo per utilizzarlo sia in Maps che in Earth utilizzando <description> anziché <ExtendedData>. È anche facile convertire questo esempio di codice in qualsiasi altro linguaggio di programmazione che supporti XML.

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

Torna all'inizio