Osmxapi で任意地区の OpenStreetMap を HTTP 取得
OpenStreetMap には、任意地区のデータを HTTP GET で取得できる API があります。これを使って、小さな地域の OpenStreetMap を Shapefile として取得するスクリプトを作ってみました。
The OSM Extended API (or osmxapi, pronounced OSM zappy) is an InformationFreeway service, based on a modified version of the standard API, that provides enhanced search and querying capabilities.
Xapi - OpenStreetMap Wiki
という API があります。geotools.rb を使って、OpenStreetMap の LineString データ(OpenStreetMap のフォーマットで言う way データ) を Shapefile に落とすスクリプトを作ってみました。
スクリプト
# osm-rest.rb # このコードは、LineString の数が 40 本程度の取得までしか使えない # (REXML のパフォーマンスの問題か、処理が遅い。) $KCODE = 'u' require 'uri' require 'open-uri' require 'rexml/document' require 'geotools' def collect_tags(e) tags = {} e.each_element('tag') do |tag| tags[tag.attribute('k').value] = tag.attribute('v').value end tags end def create_geometry(doc, e) wkt = "LINESTRING (" e.each_element('nd') do |nd| id = nd.attribute('ref').value node = REXML::XPath.first(doc, "//osm/node[@id='#{id}']") wkt += "#{node.attribute('lon').value} #{node.attribute('lat').value}, " end wkt = wkt.chop.chop + ")" Geo::import_wkt_geometry(wkt) end bbox = [9.75, 52.35, 9.76, 52.36] uri = "http://www.informationfreeway.org/api/0.5/*%5bbbox%3d#{bbox[0]},#{bbox[1]},#{bbox[2]},#{bbox[3]}%5d" doc = REXML::Document.new(open(uri).read).root print "Downloaded the data. constructing line data.\n" $stdout.flush Geo::FeatureList.open('osm-rest.shp') do |w| ways = REXML::XPath.match(doc, '//osm/way') count = 0 ways.each do |way| print "#{sprintf('%.2f', 100.0 * count / ways.size)}% of #{ways.size} finished.\n" $stdout.flush tags = collect_tags(way) geom = create_geometry(doc, way) w.write({:the_geom => geom, :tags => tags.inspect}) count += 1 end end
スクリプトの中の配列 bbox で、データの包含矩形を変更することができます。
このスクリプトは実行速度が遅いです。これは、
- Osmxapi の反応がちょっと遅い。
- REXML の XPath 処理がちょっとおそい
というあたりが原因ではないかと考えられます。(ただし、きちんと切り分けはしていません。)
感想
この API、なかなか分かりやすくてさわやかだと思いました。戻ってくるデータのデータモデルも、これ以上単純にはできないほど単純なのもので、美しいものだと感じました。
一方で、OpenStreetMap から大量のデータを取得したい場合には、やはり planet-latest.osm.gz を取得して、XPath などに頼らずにもう少し高速な手段で way と 構成 node を組み合わせる処理を実現する必要があるように感じました。XPath の高速な処理系を試してみるという別解もあるかもしれません。