Как кодировать XML в шейп-файлы ESRI с помощью Python?

Я подготовил следующий скрипт Python для этого XML в шейп-файлы ESRI. Отправной точкой для сценария был этот пост.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Requires pyshp: https://pypi.python.org/pypi/pyshp
#
# Conversion for http://daten.berlin.de/datensaetze/liste-der-gedenktafeln-berlin
# File: http://gedenktafeln-in-berlin.de/index.php?id=31&type=123
#

from xml.etree import ElementTree
from datetime import datetime
import shapefile
import os


def get_value(list, index, default):
    value = list[index]
    if value is None:
        value = default
    else:
        value = value.text
        if value is None:
            value = default
        else:
            # value = value.replace(u'\xdf', u' ')
            value = value.encode("utf-8")
    return value



def add_shape(writer, attributes):
    uid = int(get_value(attributes, 0, 0))
    url = get_value(attributes, 1, "")
    tstamp = get_value(attributes, 2, None)
    if tstamp is not None:
        tstamp = datetime.strptime(tstamp, '%d.%m.%Y')
    ortsteil = get_value(attributes, 3, "")
    strasse = get_value(attributes, 4, "")
    longitude = get_value(attributes, 5, None)
    latitude = get_value(attributes, 6, None)
    Name = get_value(attributes, 7, "")
    inhalt = get_value(attributes, 8, "")
    erlauterung = get_value(attributes, 9, "")
    swo = get_value(attributes, 10, "")
    literatur = get_value(attributes, 11, "")
    personen = get_value(attributes, 12, "")
    entfernt = int(get_value(attributes, 13, 0))

    if longitude is not None or latitude is not None:
        longitude = float(longitude)
        latitude = float(latitude)

        # Fix interchanged coordinates
        temp = 0
        if longitude > latitude:
            temp = latitude
            latitude = longitude
            longitude = temp

        # Add coordinates
        writer.point(longitude, latitude)

    # Add attributes
    writer.record(uid, url, tstamp, ortsteil, strasse, Name, inhalt, erlauterung, swo, literatur, personen, entfernt)




xml_file = 'gedenktafeln.xml'
shape_file = 'gedenktafeln.shp'
projection = 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]'

tree = ElementTree.parse(xml_file)
writer = shapefile.Writer(shapefile.POINT)

writer.field('uid', fieldType = 'N', size = 5, decimal = 0)
writer.field('url', fieldType = 'C', size = 255)
writer.field('tstamp', fieldType = 'C', size = 19) # Type 'D' seems to be not working here.
writer.field('ortsteil', fieldType = 'C', size = 200)
writer.field('strasse', fieldType = 'C', size = 200)
writer.field('Name', fieldType = 'C', size = 255)
writer.field('inhalt', fieldType = 'C', size = 255)
writer.field('erlauterung', fieldType = 'C', size = 255)
writer.field('swo', fieldType = 'C', size = 255)
writer.field('literatur', fieldType = 'C', size = 255)
writer.field('personen', fieldType = 'C', size = 255)
writer.field('entfernt', fieldType = 'N', size = 1, decimal = 0)

root = tree.getroot()
shapes = root.getchildren()

for shape in shapes:
    attributes = shape.getchildren()
    add_shape(writer, attributes)

try:
    writer.save(shape_file)
except Exception, e:
    print "ortsteil: " + ortsteil
    print "strasse: " + strasse
    print "Name: " + Name
    print "inhalt: " + inhalt
    print "erlauterung: " + erlauterung
    print "swo: " + swo
    print "literatur: " + literatur
    print "personen: " + personen
    print "entfernt: " + entfernt
    raise

# create the PRJ file
with open(os.path.splitext(shape_file)[0] + os.extsep + 'prj', 'w') as prj:
    prj.write(projection)

Остались некоторые проблемы:

  1. Специальные символы кодируются не так, как ожидалось. Я не уверен, что value = value.encode("utf-8") правильно - пожалуйста, прокомментируйте это. // Thanks to ptrv
  2. Отрезан url. // Resolved by blah238
  3. Координаты не в Берлине, а в Потсдаме. Это может быть ошибка в исходных данных. Или я использую неправильные projection настройки.

Чтобы проверить данные, я преобразовал их в GeoJSON, чтобы вы могли просматривать их онлайн.


person JJD    schedule 11.04.2014    source источник


Ответы (2)


Я могу только прокомментировать вашу вторую проблему, которая заключается в том, что ваши значения url обрезаются. Вам нужно указать длину поля, например. writer.field('url', size=255)

person blah238    schedule 11.04.2014
comment
Хороший. Работает как шарм. Я обновил онлайн-пример. - person JJD; 13.04.2014
comment
Я только что заметил, что другие поля с большим содержанием тоже усекаются. В документации PyShp явно не указывается максимальная длина для fieldType = 'C' (Персонаж). Методом проб и ошибок я выяснил, что size = 255 работает, тогда как большие числа приводят к этой ошибке: struct.error: ubyte format requires 0 <= number <= 255. Можете ли вы сказать, как я могу хранить более длинные тексты в шейп-файле? - person JJD; 17.04.2014
comment
Ограничение длины поля шейп-файла составляет 254 символа в соответствии с en.wikipedia.org/wiki/Shapefile#Limitations< /а>. - person blah238; 17.04.2014

Для первой проблемы попробуйте удалить строку value = value.replace(u'\xdf', u' ')

Это сработало для меня, и я успешно смог создать шейп-файл с атрибутами, содержащими специальные символы.

person ptrv    schedule 16.04.2014
comment
На самом деле, это выглядит хорошо, когда я открываю шейп-файл в QGIS. Проблема, похоже, заключается в преобразовании в GeoJSON, которое я делаю с помощью ogr2ogr. - person JJD; 17.04.2014
comment
Ой! На этот раз почему-то сработало.. Может потому, что я указал атрибут fieldType. Неясно. - person JJD; 17.04.2014
comment
Тем не менее, я рекомендую удалить эту строку. value = value.encode("utf-8") выполняет преобразование. - person ptrv; 17.04.2014
comment
Спасибо. Я сделал. Я просто забыл сделать это здесь по вопросу. - person JJD; 17.04.2014