Conversão de arquivos CSV em KML

Mano Marks, equipe de APIs do Google Geo
Março de 2008

Objetivo

Neste tutorial, descrevemos as noções básicas de como criar um KML a partir de dados de valores separados por vírgulas (CSV, na sigla em inglês) usando Python. Os dados CSV são um dos formatos de arquivo mais usados hoje. A maioria das planilhas e bancos de dados pode ler e gravar arquivos CSV. O formato simples pode ser editado em um editor de texto. Muitas linguagens de programação, como Python, têm bibliotecas especiais para ler e gravar arquivos CSV. Portanto, ele é uma ótima mídia para a troca de grandes quantidades de dados.

As amostras de código neste tutorial estão em Python, mas podem ser adaptadas à maioria das outras linguagens de programação. Neste tutorial, usamos códigos de Endereços de geocodificação para uso em KML para transformar um endereço em coordenadas de longitude/latitude. Ele também usa o novo elemento <ExtendedData> do KML 2.2 e aproveita o modelo de balão descrito em Adicionar dados personalizados. Assim, o KML produzido não é atualmente compatível com o Google Maps ou outros aplicativos que consomem KML, mas o código pode ser adaptado para produzir KML compatível com Maps.

Dados de amostra

Para este tutorial, use o arquivo google-addresses.csv como um arquivo CSV de amostra. Esse arquivo tem todos os endereços, números de telefone e números de fax dos vários escritórios do Google nos EUA. Veja o texto do arquivo:

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,

Observe como cada linha é uma série de strings de texto separadas por vírgulas. Cada vírgula limita o campo, cada linha tem o mesmo número de vírgulas. A primeira linha contém os nomes dos campos em ordem. Por exemplo, o primeiro bloco de texto em cada linha é o campo "Escritório", o segundo "Address1" etc. O Python pode transformá-lo em uma coleção de dicts chamada DictReader, que permite percorrer cada linha. Essa amostra de código depende do conhecimento prévio da estrutura dos dados, mas é possível adicionar alguns gerenciadores básicos para transmitir a estrutura dos campos dinamicamente.

Como analisar o arquivo CSV

O módulo xml.dom.minidom do Python fornece ótimas ferramentas para criar documentos XML e, como o KML é XML, você o usará muito neste tutorial. Crie um elemento com createElement ou createElementNS e anexe a outro elemento com appendChild. Estas são as etapas para analisar o arquivo CSV e criar um arquivo KML.

  1. Importe Geocoding_for_kml.py no seu módulo.
  2. Crie um DictReader para os arquivos CSV. O DictReader é uma coleção de dicts, uma para cada linha.
  3. Crie o documento usando xml.dom.minidom.Document() do Python.
  4. Criar o elemento raiz <kml> usando createElementNS.
  5. Anexe ao documento.
  6. Crie um elemento <Document> usando createElement.
  7. Anexe-o ao elemento <kml> usando appendChild.
  8. Para cada linha, crie um elemento <Placemark> e anexe-o ao elemento <Document>.
  9. Para cada coluna em cada linha, crie um elemento <ExtendedData> e o anexe ao elemento <Placemark> criado na etapa 8.
  10. Crie um elemento <Data> e o anexe ao elemento <ExtendedData>. Atribua um elemento de nome ao elemento <Data> e atribua a ele o valor do nome da coluna usando setAttribute.
  11. Crie um elemento <value> e o anexe ao elemento <Data>. Crie um nó de texto e atribua o valor da coluna usando createTextNode. Anexe o nó de texto ao elemento <value>.
  12. Crie um elemento <Point> e o anexe ao elemento <Placemark>. Crie um elemento <coordinates> e anexe ao elemento <Point>.
  13. Extraia o endereço da linha para que ele seja uma única string neste formato: Address1,Address2,City,State,Zip. A primeira linha seria 1600 Amphitheater Parkway,,Mountain View,CA,94043. Não há problema se houver vírgulas ao lado uma da outra. Para isso, é preciso ter conhecimento prévio da estrutura do arquivo CSV e quais colunas constituem o endereço.
  14. Geocodifique o endereço usando o código Geocoding_for_KML.py, descrito em Como geocodificar endereços para uso em KML. Isso retorna uma string, que é a longitude e a latitude do local.
  15. Crie um nó de texto e atribua a ele o valor das coordenadas na etapa 14 e, em seguida, anexe-o ao elemento <coordinates>.
  16. Grave o documento KML em um arquivo.
  17. Se você passar uma lista de nomes de coluna como argumentos para o script, o script adicionará elementos nessa ordem. Se não nos importarmos com a ordem dos elementos, podemos usar dict.keys() para produzir uma list. No entanto, dict.keys() não preserva a ordem original do documento. Para usar esse argumento, transmita a lista de nomes de campos como uma lista separada por vírgulas, desta forma:
    python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax

Exemplo de código Python

Veja abaixo um exemplo de código para criar um arquivo KML a partir de um arquivo CSV usando o Python 2.2. Você também pode fazer o download dele clicando aqui.


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

Exemplo de KML criado

Veja abaixo um exemplo do KML criado por esse script. Observe como alguns elementos <value> têm apenas espaços em branco. Isso ocorre porque o campo não tem dados. Também é possível fazer o download da amostra completa neste link.

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

Captura de tela

Veja abaixo uma captura de tela mostrando como é esse arquivo KML no Google Earth. Como cada elemento <Placemark> não tem <BalloonStyle><text> e nenhum elemento <description>, o balão é padronizado para um estilo de tabela, desenhando nos elementos <Data>.

Captura de tela do KML criado por este script

Consideração de geocodificação

Isso foi mencionado em "Endereços de geocodificação para uso em KML", mas vale a pena repetir. Suas solicitações de geocodificação estarão sujeitas à taxa máxima de consulta do geocodificador e a 15.000 consultas por dia com base no seu IP. Além disso, um código de status 620 será retornado pelo geocodificador se você fizer uma consulta mais rápida do que ele consegue processar. Veja uma lista completa dos códigos de status aqui. Para não enviar consultas muito rapidamente ao geocodificador, especifique um atraso entre cada solicitação. Esse atraso pode ser aumentado sempre que você receber um status 620. Além disso, use um loop while para garantir que você geocodificou um endereço antes de iterar para o próximo. Isso significa que, se o arquivo CSV for muito grande, talvez seja necessário modificar o código de geocodificação ou acompanhar a velocidade de criação dos marcadores e desacelerar se for muito rápido.

Conclusão

Agora você pode usar Python para criar um arquivo KML a partir de um arquivo CSV. Usando o código fornecido, o arquivo KML só funcionará no Google Earth. Modifique-o para funcionar no Maps e no Earth usando <description> em vez de <ExtendedData>. Também é fácil converter esse exemplo de código em qualquer outra linguagem de programação que ofereça suporte a XML.

Agora que você terminou de converter todos os seus arquivos CSV para KML, confira outros artigos KML, como Usar PHP e MySQL para criar KML e o artigo do Guia do desenvolvedor do Google sobre ExtendedData, Como adicionar dados personalizados.

Voltar ao início