Created
December 19, 2011 23:20
-
-
Save samatjain/1499378 to your computer and use it in GitHub Desktop.
Bottle-powered version of OSM XML → JSON proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import json | |
import urlparse | |
import bottle | |
import requests | |
from bottle import request, response, route | |
from bottle import install, uninstall | |
from lxml import etree | |
from json import dumps as json_dumps | |
class JSONAPIPlugin(object): | |
name = 'jsonapi' | |
api = 1 | |
def __init__(self, json_dumps=json_dumps): | |
uninstall('json') | |
self.json_dumps = json_dumps | |
def apply(self, callback, context): | |
dumps = self.json_dumps | |
if not dumps: return callback | |
def wrapper(*a, **ka): | |
r = callback(*a, **ka) | |
# Attempt to serialize, raises exception on failure | |
json_response = dumps(r) | |
# Set content type only if serialization succesful | |
response.content_type = 'application/json' | |
# Wrap in callback function for JSONP | |
callback_function = request.query.get('callback') | |
if callback_function: | |
json_response = ''.join([callback_function, '(', json_response, ')']) | |
return json_response | |
return wrapper | |
install(JSONAPIPlugin()) | |
@route('/<type>/<id:int>') | |
def fetch(type, id): | |
if type not in ('node', 'way', 'relation'): | |
abort('500', 'Primitive must be node, way, or relation') | |
r = _fetch(type, id) | |
if r is None: | |
abort('404', 'Object not found') | |
return r | |
def _fetch(item_type, item_id): | |
url = 'http://api.openstreetmap.org/api/0.6/%s/%d' % (item_type, item_id) | |
headers = {'user-agent': 'OSMPlaces JSON API Proxy (Contact: http://samat.org/contact.html)'} | |
response = requests.get(url, headers=headers) | |
# Request failed; may not exist, server error, etc | |
if response.status_code != requests.codes.ok: | |
return None | |
out = {} | |
root = etree.fromstring(response.content.encode('utf-8')) | |
i = root[0] # Skip <osm/>; should we be iterating over all children here? | |
out['type'] = i.tag # Save whether node, way, relation | |
# Copy attributes on node/way/relation tag | |
for k, v in i.items(): | |
# Store certain keys as int, float, bool, etc | |
if k in ('changeset', 'uid', 'version', 'id'): | |
v = int(v) | |
if k in ('lat', 'lon'): | |
v = float(v) | |
if k in ('visible',): | |
v = True if v.lower() == 'true' else 'false' | |
out[k] = v | |
# Copy tags | |
tags = {} | |
for t in i.iterfind('tag'): | |
k, v = t.get('k'), t.get('v') | |
tags[k] = v | |
if tags: | |
out['tags'] = tags | |
# Create list of nodes for ways | |
nodes = [] | |
for t in i.iterfind('nd'): | |
nodes.append(int(t.get('ref'))) | |
if nodes: | |
out['nodes'] = nodes | |
# Copy members for relations | |
members = [] | |
for t in i.iterfind('member'): | |
a = {} | |
for k, v in t.items(): | |
if k in ('ref',): | |
v = int(v) | |
a[k] = v | |
members.append(a) | |
if members: | |
out['members'] = members | |
return out | |
application = bottle.default_app() | |
if __name__ == '__main__': | |
from bottle import run | |
run(reloader=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment