Преобразование файлов CSV в KML

Мано Маркс, команда Google Geo API
март 2008 г.

Задача

В этом руководстве изложены основы создания KML из данных, разделенных запятыми (CSV) , с помощью Python. Данные CSV — один из самых распространенных сегодня форматов файлов. Большинство электронных таблиц и баз данных могут как читать, так и записывать файлы CSV. Его простой формат можно редактировать в текстовом редакторе. Многие языки программирования, такие как Python, имеют специальные библиотеки для чтения и записи файлов CSV. Поэтому он является отличным средством для обмена большими объемами данных.

Хотя примеры кода в этом руководстве написаны на Python, их можно адаптировать для большинства других языков программирования. В этом руководстве используется код из раздела «Геокодирование адресов для использования в KML» , чтобы преобразовать адрес в координаты долготы/широты. Он также использует новый элемент <ExtendedData> из KML 2.2 и преимущества шаблонов всплывающих окон, описанных в разделе Добавление пользовательских данных . Таким образом, созданный KML в настоящее время не поддерживается в Google Maps или других приложениях, использующих KML, но код можно адаптировать для создания KML, совместимого с Maps.

Образец данных

В этом руководстве используйте файл google-addresses.csv в качестве образца CSV-файла. В этом файле есть все адреса, номера телефонов и факсов различных офисов Google в США. Вот текст файла:

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,

Обратите внимание, что каждая строка представляет собой набор текстовых строк, разделенных запятыми. Каждая запятая ограничивает поле; каждая строка имеет одинаковое количество запятых. Первая строка содержит названия полей по порядку. Например, первый блок текста в каждой строке — это поле «Офис», второй — «Адрес1» и т. д. Python может превратить это в набор dicts , называемый DictReader , который позволяет вам проходить по каждой строке. Этот пример кода основан на том, что вы заранее знаете структуру своих данных, но вы можете добавить некоторые базовые обработчики для динамической передачи структуры поля.

Разбор CSV-файла

Модуль Python xml.dom.minidom предоставляет отличные инструменты для создания XML-документов, а поскольку KML — это XML, вы будете довольно часто использовать его в этом руководстве. Вы создаете элемент с помощью createElement или createElementNS и добавляете к другому элементу с помощью appendChild . Это шаги для анализа файла CSV и создания файла KML.

  1. Импортируйте geocoding_for_kml.py в свой модуль.
  2. Создайте DictReader для файлов CSV. DictReader — это набор dicts , по одному на каждую строку.
  3. Создайте документ, используя Python xml.dom.minidom.Document() .
  4. Создайте корневой элемент <kml> с помощью createElementNS.
  5. Приложить к документу .
  6. Создайте элемент <Document> с помощью createElement .
  7. Добавьте его к элементу <kml> с помощью appendChild .
  8. Для каждой строки создайте элемент <Placemark> и добавьте его к элементу <Document> .
  9. Для каждого столбца в каждой строке создайте элемент <ExtendedData> и добавьте его к элементу <Placemark> , созданному на шаге 8.
  10. Создайте элемент <Data> и добавьте его к элементу <ExtendedData> . Дайте элементу <Data> атрибут имени и присвойте ему значение имени столбца, используя setAttribute .
  11. Создайте элемент <value> и добавьте его к элементу <Data> . Создайте текстовый узел и присвойте ему значение столбца с помощью createTextNode . Добавьте текстовый узел к элементу <value> .
  12. Создайте элемент <Point> и добавьте его к элементу <Placemark> . Создайте элемент <coordinates> и присоедините его к элементу <Point> .
  13. Извлеките адрес из строки, чтобы он представлял собой одну строку в следующем формате: Address1,Address2,City,State,Zip. Таким образом, первый ряд будет 1600 Amphitheater Parkway,,Mountain View,CA,94043 . Это нормально, если есть запятые рядом друг с другом. Обратите внимание, что для этого требуется предварительное знание структуры CSV-файла и того, какие столбцы составляют адрес.
  14. Геокодируйте адрес с помощью кода geocoding_for_kml.py , описанного в разделе Геокодирование адресов для использования в KML . Это возвращает строку, которая представляет собой долготу и широту местоположения.
  15. Создайте текстовый узел и присвойте ему значение координат на шаге 14, затем добавьте его к элементу <coordinates> .
  16. Запишите документ KML в файл.
  17. Если вы передадите список имен столбцов в качестве аргументов сценарию, сценарий добавит элементы в указанном порядке. Если бы нас не заботил порядок элементов, мы могли бы использовать dict.keys() для создания list . Однако dict.keys() не сохраняет исходный порядок документа. Чтобы использовать этот аргумент, передайте список имен полей в виде списка, разделенного запятыми, например:
    python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax

Пример кода Python

Пример кода для создания файла KML из файла CSV с использованием Python 2.2 показан ниже. Вы также можете скачать его здесь .


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 создан

Образец файла KML, созданного этим сценарием, показан ниже. Обратите внимание, что некоторые элементы <value> содержат только пробелы. Это потому, что в поле не было никаких данных. Вы также можете скачать полный образец здесь .

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

Скриншот

Ниже приведен скриншот того, как этот файл KML выглядит в Google Планета Земля. Поскольку каждый элемент <Placemark <Placemark> не имеет элементов <BalloonStyle><text> и <description> , всплывающая подсказка по умолчанию использует стиль таблицы, опираясь на элементы <Data> .

Скриншот KML, созданный этим скриптом

Рассмотрение геокодирования

Это упоминалось в разделе «Геокодирование адресов для использования в KML», но стоит повторить. К вашим запросам на геокодирование будет применяться максимальная частота запросов геокодера и 15 000 запросов в день в зависимости от вашего IP-адреса. Кроме того, геокодер вернет код состояния 620 , если вы запросите его быстрее, чем он может обработать. (Полный список кодов состояния доступен здесь .) Чтобы не слишком быстро отправлять запросы геокодеру, можно указать задержку между каждым запросом геокодирования. Вы можете увеличивать эту задержку каждый раз, когда получаете статус 620 , и использовать цикл while , чтобы убедиться, что вы успешно геокодировали адрес, прежде чем переходить к следующему. Это означает, что если ваш CSV-файл очень большой, вам, возможно, придется либо изменить код геокодирования, либо отслеживать скорость создания меток и замедлить ее, если вы работаете слишком быстро.

Заключение

Теперь вы можете использовать Python для создания файла KML из файла CSV. При использовании предоставленного кода файл KML будет работать только в Google Планета Земля. Вы можете изменить его для работы как в Картах, так и в Google Планета Земля, используя <description> вместо <ExtendedData> . Этот пример кода также легко преобразовать в любой другой язык программирования, поддерживающий XML.

Теперь, когда вы завершили преобразование всех ваших CSV-файлов в KML, вы можете ознакомиться с другими статьями KML, такими как Использование PHP и MySQL для создания KML и статьей Руководства разработчика Google о расширенных данных, добавлении пользовательских данных .

Вернуться к вершине