Skip to content

Instantly share code, notes, and snippets.

@yehara
Created March 15, 2011 06:08
Show Gist options
  • Save yehara/870384 to your computer and use it in GitHub Desktop.
Save yehara/870384 to your computer and use it in GitHub Desktop.
KML データを JSON に変換するスクリプト
#!ruby
# -*- encoding: UTF-8 -*-
require "rubygems"
require "rexml/document"
require "rexml/streamlistener"
require "sqlite3"
require "pr_geohash"
include REXML
class KmlListener
include StreamListener
@@placemark_context = ['kml', 'Document', 'Folder', 'Placemark']
@@name_context = @@placemark_context + ['name']
@@description_context = @@placemark_context + ['description']
@@coordinate_context = @@placemark_context + ['Point', 'coordinates']
def initialize
@context = []
@array = []
end
def array
@array
end
def tag_start(tag, attrs)
@context.push tag
case tag
when "kml"
@id = 0
when "Placemark"
@place = Hash::new
@id += 1
@place["id"] = @id
@place["name"] = ""
@place["description"] = ""
end
end
def tag_end(tag)
case tag
when "Placemark"
# puts @place
@array.push @place
end
@context.delete_at -1
end
def cdata(content)
case @context.last
when "name"
if @context == @@name_context then
@place["name"] = content
end
when "description"
if @context == @@description_context then
/<b>住所:<\/b>\s*(.*)\s*<\/div>/m =~ content
@place["description"] = $1.chomp
end
end
end
def text(text)
case @context.last
when "coordinates"
if @context == @@coordinate_context then
/([-0-9\.]+),([-0-9\.]+)(?:,([-0-9\.]+))/m =~ text
@place["lng"] = $1.to_f
@place["lat"] = $2.to_f
end
end
end
end
listener = KmlListener.new
Document.parse_stream($stdin, listener)
db = SQLite3::Database.new("shelter.db")
db.execute("create table if not exists places (id integer primary key, name text, lat real, lng real, detail text);")
db.execute("create table if not exists geohash (geohash text primary key, lat real, lng real, glat real, glng real, length integer, center_count integer, neighbor_count integer);")
db.execute("create table if not exists place_geohashes (places_id integer references places(id), geohash text references geohash(geohash), center integer);")
db.execute("delete from place_geohashes;")
db.execute("delete from geohash;")
db.execute("delete from places;")
db.execute("vacuum;")
db.transaction do
array = listener.array
array.each {|place|
next if !place.key?('lat') || !place.key?('lng')
p place["id"]
db.execute("insert or replace into places values (:id, :name, :lat, :lng, :detail);", place["id"], place["name"], place["lat"], place["lng"], place["description"])
[4, 5, 6].each {|l|
center = GeoHash.encode(place["lat"], place["lng"], l)
center_pos = GeoHash.decode(center)
db.execute("insert or replace into geohash values (:geohash, :lat, :lng, 0, 0, :length, 0, 0)", center, (center_pos[0][0]+center_pos[1][0])/2, (center_pos[0][1]+center_pos[1][1])/2, l)
GeoHash.neighbors(center).each {|n|
n_pos = GeoHash.decode(n)
db.execute("insert or replace into geohash values (:geohash, :lat, :lng, 0, 0, :length, 0, 0)", n, (n_pos[0][0]+n_pos[1][0])/2, (n_pos[0][1]+n_pos[1][1])/2, l)
}
}
}
array.each {|place|
next if !place.key?('lat') || !place.key?('lng')
p place["id"]
[4, 5, 6].each {|l|
center = GeoHash.encode(place["lat"], place["lng"], l)
db.execute("insert into place_geohashes values (:placesid, :geohash, 1)", place["id"], center)
db.execute("update geohash set center_count=center_count+1, glat=(glat*center_count+:lat)/(center_count+1), glng=(glng*center_count+:lng)/(center_count+1) where geohash=:geohash", place["lat"], place["lng"], center)
GeoHash.neighbors(center).each {|n|
n_pos = GeoHash.decode(n)
db.execute("insert into place_geohashes values (:placesid, :geohash, 0)", place["id"], n)
db.execute("update geohash set neighbor_count=neighbor_count+1 where geohash=:geohash", n)
}
}
}
end
db.execute("vacuum;")
db.close
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment