Конвертор из .osm(.bz2) в Питон и все доступные ему форматы

Понадобилось конвертировать osm в Json и сделать фильтр по тегам, написал вот такой простой скрипт, который можно использовать по своему усмотрению:

https://bitbucket.org/siberiano/osm2python

В репозитории есть пример, как конвертировать файл из .osm.bz2 в .json.bz2, osm2json. Вызывать так:

$ python osm2json.py myfile.osm.bz2 myfile.json.bz2

Размеры файлов на входе и выходе примерно равны.

Пример программного использования: открываем файл и пишем обработчик элементов (элементы - корневые, то есть точки отдельно, пути отдельно, отношения. Остальные - теги, члены отношений, точки путей - будут внутри выданных элементов.)

import bz2
import urllib
import osm2py

# откроем потоком и будем потоково распаковывать планету
infile = bz2.BZ2Decompressor(urllib.urlopen('http://planet.openstreetmap.org/planet-latest.osm.bz2'))

# нужны пути, чтобы в них был тег highway=*
def callback(element):
    if element.get('children') and element['name'] == 'way': # see if the element is a highway
        for child in element.get('children'):
            if any([t.get('k') == 'highway' for t in child.get('children')]):
               print element  # элемент печатаем в stdout

osm2py.parse_file(infile, callback)

Зачем это нужно? JSON удобнее парсить, чем XML, можно хранить в БД NoSQL, можно читать и править в редакторе. Можно импортировать в Питон или в Яваскрипт (а не-броузерный яваскрипт уже распространяется!)

TODO:

  • комментарии
  • рефакторить библиотеку, чтобы не переписывать global output_callback (нужен совет)

Хоть в Питоне,JSON,Javascript я ничего не понимаю, но всё-таки считаю, что репозиторий нужно сделать публичным.

Точно, забыл убрать галочку. Спасибо! Теперь публичный.

Добавил

  1. пример конвертации в json в папке sample
  2. скрипт mongo.py, которым я импортирую в MongoDB
    На ноутбуке у меня 12-меговый дамп области импортируется за пару минут.

https://bitbucket.org/siberiano/osm2python

Добавил модуль, который рендерит в файлы .osm при помощи движка шаблонов Django 1.3.

На входе - dict. На выходе - либо строка (.render(), .dumps()), либо в файловый поток (.dump())


import bz2
from osm2py import template
doc = {
    'nodes': [{'id': ..., 'tags': {'highway': 'primary'}, ...}, {'id': ...}],
    'ways': [...],
    'relations': [...],
}
osmbz2 = bz2.BZ2File('mymap.osm.bz2', 'w')
template.dump(doc, osmbz2)

Также умеет сделать из точек путь:

>>> nodes = [{u'changeset': 5423505, 
>>>  u'id': 848517446,
>>>  u'lat': 54.753465400000003,
>>>  u'lon': 83.128522599999997,
>>>  u'timestamp': u'2010-08-07T10:39:15Z',
>>>  u'uid': 237049,
>>>  u'user': u'siberiano',
>>>  u'version': u'1'},
>>> {u'changeset': 7016890,
>>>  u'id': 1109991376,
>>>  u'lat': 54.753030099999997,
>>>  u'lon': 83.134304200000003,
>>>  u'timestamp': u'2011-01-19T03:13:30Z',
>>>  u'uid': 237045,
>>>  u'user': u'Magomogo',
>>>  u'version': u'1'}]

>>> template.make_dummy_way(nodes, {'highway': 'motorway'})
{'nodes': [{u'changeset': 5423505,
            u'id': 848517446,
            u'lat': 54.753465400000003,
            u'lon': 83.128522599999997,
            u'timestamp': u'2010-08-07T10:39:15Z',
            u'uid': 237049,
            u'user': u'siberiano',
            u'version': u'1'},
           {u'changeset': 7016890,
            u'id': 1109991376,
            u'lat': 54.753030099999997,
            u'lon': 83.134304200000003,
            u'timestamp': u'2011-01-19T03:13:30Z',
            u'uid': 237045,
            u'user': u'Magomogo',
            u'version': u'1'}],
 'ways': [{'id': 1,
           'nodes': [{'ref': 848517446},
                     {'ref': 1109991376}],
           'tags': {'highway': 'motorway'}}]}

https://bitbucket.org/siberiano/osm2python

Стал обновлять конвертер. Нашёл на ГитХабе какой-то, но там код ужасный и не поправишь ничего. Решил, что лучше день потерять, потом за 5 минут долететь… Теперь конвертер может и экспортировать файлы, не только считывать.

Теперь есть 2 класса, работа с ними - проще, чем раньше. Один выдаёт словари, другой - красивенькие объекты.

d = SmartOsmDocument()
d.load(open(sys.argv[1]))  # открываем файл, который указан в командной строке
d.dump(open('test.osm', 'w'))

Вместо обычного файла питоном можно открывать и bz2, в общем load принимает любой объект с интерфейсом файла.
И выдаёт тоже в любой подобный.

Единственное что ограничено пока - это возможности генерировать новые данные. То есть создать точку или путь будет затруднительно (придётся сгенерировать словарь).

Немного упростил модуль, теперь не надо возиться с классами.

>>> from osm2py import load_osm
>>> load_osm(open('my_file.osm'))

выдаст список словарей, в которых представлены XML элементы. Чтобы как-то обрабатывать их и сохранять в нужном вам виде, нужно написать функцию обработчик, например, по умолчанию функция просто записывает элемент в родительские дети:

		def load_callback(current, parent):
			parent['children'].append(current)

Можно переопределить функцию, чтобы она, например, записывала в базу данных.

Чтобы было проще работать с элементами, нужно определить фильтр. Он будет фильтровать узлы, но не включая дочерние. Например, хотим узнать только все тэги:

def cb(elt, parent=None):
    print "{k}: {v}".format(elt['attrs'])

flt = lambda elt: elt['name'] == 'tag'

load_osm(open('my_file.osm'), cb, flt)

Напечатает все тэги последовательно. Как посчитать тэги самому, оставляю в качестве домашнего задания.

siberiano
Синхронизировался с bitbucket - в папке только модули init.py, osm_json.py и tree.py; модули osm2py.py, mongo.py не вижу (раньше с Mercurial не сталкивался). Теперь надо работать с init.py ?