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

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

Цель

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

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

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

В этом руководстве в качестве примера используется файл google-addresses.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,

Обратите внимание, что каждая строка представляет собой последовательность текстовых строк, разделённых запятыми. Каждая запятая разделяет поле; в каждой строке одинаковое количество запятых. Первая строка содержит названия полей по порядку. Например, первый блок текста в каждой строке — это поле «Office», второй — «Address1» и т. д. 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. Создайте документ с помощью xml.dom.minidom.Document() Python.
  4. Создайте корневой элемент <kml> с помощью createElementNS.
  5. Добавить к документу .
  6. Создайте элемент <Document> с помощью createElement .
  7. Добавьте его к элементу <kml> с помощью appendChild .
  8. Для каждой строки создайте элемент <Placemark> и добавьте его к элементу <Document> .
  9. Для каждого столбца в каждой строке создайте элемент <ExtendedData> и добавьте его к элементу <Placemark> , созданному на шаге 8.
  10. Создайте элемент <Data> и добавьте его к элементу <ExtendedData> . Добавьте к элементу <Data> атрибут name и присвойте ему значение имени столбца с помощью setAttribute .
  11. Создайте элемент <value> и добавьте его к элементу <Data> . Создайте текстовый узел и присвойте ему значение столбца с помощью createTextNode . Добавьте текстовый узел к элементу <value> .
  12. Создайте элемент <Point> и добавьте его к элементу <Placemark> . Создайте элемент <coordinates> и добавьте его к элементу <Point> .
  13. Извлеките адрес из строки, чтобы он представлял собой одну строку в следующем формате: Адрес1, Адрес2, Город, Штат, Почтовый индекс. Таким образом, первая строка будет выглядеть так: 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 Earth. Поскольку у каждого элемента <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 по ExtendedData, Добавление пользовательских данных .

Вернуться наверх