Mit dem nationalen Download-Service für numerische Landinformationen können Sie Daten erhalten, die vom Ministerium für Land, Infrastruktur, Verkehr und Tourismus verwaltet werden. Dieses Mal werde ich die Koordinaten auf Google Map anhand von Eisenbahndaten zeichnen.
Demo: http://needtec.sakura.ne.jp/railway_location/railway
GIT: https://github.com/mima3/railway_location
Eisenbahndaten können von der folgenden Seite heruntergeladen werden.
** Nationale Landnummerninformationen Eisenbahndaten ** http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N02-v2_2.html
Informationen zur Verwendung von XML in der heruntergeladenen Datei finden Sie im Folgenden. http://nlftp.mlit.go.jp/ksj/gml/product_spec/KS-PS-N02-v2_1.pdf
Einfach ausgedrückt, enthalten Eisenbahndaten Informationen, die die Form der Linien- und Bahnhofsinformationen anzeigen. Hier sind die wichtigen Elemente: ・ Gml: Kurvenkurveninformationen ・ Ksj: Eisenbahnabschnitt Informationen zum Eisenbahnabschnitt ・ Ksj: Station Stationsinformationen
Koordinateninformationen werden in Curve gespeichert. Die Verknüpfung zu Curve wird im Standortelement von railroadSection and Station gespeichert.
Da es schwierig ist, eine große Datenmenge in XML zu verarbeiten, wird sie vorübergehend in einer relationalen Datenbank gespeichert.
Zu diesem Zeitpunkt wird eine große XML-Datei analysiert. Wenn jedoch die gesamte XML-Datei einmal im Speicher gespeichert und analysiert wurde, steigt die Speichernutzung dramatisch an und es ist nicht möglich, sie zu verarbeiten. Verwenden Sie daher lxml.etree.iterparse, um nacheinander zu verarbeiten.
Beim Parsen von N02-XX.xml mit lxml.etree.itreparse tritt jedoch ein Fehler auf. Dies liegt daran, dass das XML folgende Zeilen enthält:
xmlns:schemaLocation="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app KsjAppSchema-N02-v2_0.xsd">
lxml betrachtet den hier angegebenen URI als ungültigen URI und gibt einen Fehler aus. Um dies zu vermeiden, muss beim Parsen von XML in lxml restore = True angegeben werden. http://stackoverflow.com/questions/18692965/how-do-i-skip-validating-the-uri-in-lxml
** Problemumgehung: **
context = etree.iterparse(
xml,
events=('end',),
tag='{http://www.opengis.net/gml/3.2}Curve',
recover=True
)
In iterparse wurde dieses Argument nach lxml == 3.4.1 eingeführt, daher müssen Sie die Version angeben, in der lxml installiert werden soll.
easy_install lxml==3.4.1
Basierend auf dem oben Gesagten erfolgt der Import des XML von Eisenbahndaten in die Datenbank wie folgt.
railway_db.py
# -*- coding: utf-8 -*-
import sqlite3
import sys
import os
# easy_install lxml==3.4.1
from lxml import etree
from peewee import *
database_proxy = Proxy()
database = None
class BaseModel(Model):
"""
Modellklassenbasis
"""
class Meta:
database = database_proxy
class Curve(BaseModel):
"""
Kurveninformationsmodell
"""
curve_id = CharField(index=True, unique=False)
lat = DoubleField()
lng = DoubleField()
class RailRoadSection(BaseModel):
"""
Modell für Informationen zum Eisenbahnabschnitt
"""
gml_id = CharField(primary_key=True)
#Da der externe Schlüssel einen Primärschlüssel oder eine eindeutige Einschränkung haben muss,
#Es kann nicht als externer Schlüssel für mehrere Daten angegeben werden.
location = CharField(index=True)
railway_type = IntegerField()
service_provider_type = IntegerField()
railway_line_name = CharField(index=True)
operation_company = CharField(index=True)
class Station(BaseModel):
"""
Stationsinformationsmodell
"""
gml_id = CharField(primary_key=True)
#Da der externe Schlüssel einen Primärschlüssel oder eine eindeutige Einschränkung haben muss,
#Es kann nicht als externer Schlüssel für mehrere Daten angegeben werden.
location = CharField(index=True)
railway_type = IntegerField()
service_provider_type = IntegerField()
railway_line_name = CharField(index=True)
operation_company = CharField(index=True)
station_name = CharField(index=True)
railroad_section = ForeignKeyField(
db_column='railroad_section_id',
rel_model=RailRoadSection,
to_field='gml_id',
index=True
)
def setup(path):
"""
Datenbankeinrichtung
@Parameterpfad Datenbankpfad
"""
global database
database = SqliteDatabase(path)
database_proxy.initialize(database)
database.create_tables([Curve, RailRoadSection, Station], True)
def import_railway(xml):
"""
Nationales Landnumerisches Institut N02-XX.Importieren Sie Routen- und Stationsinformationen aus XML
TODO:
Ineffizienter Import externer Schlüssel
@param xml XML-Pfad
"""
commit_cnt = 2000 #Fügen Sie jede hier angegebene Nummer ein
f = None
contents = None
namespaces = {
'ksj': 'http://nlftp.mlit.go.jp/ksj/schemas/ksj-app',
'gml': 'http://www.opengis.net/gml/3.2',
'xlink': 'http://www.w3.org/1999/xlink',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
}
with database.transaction():
insert_buff = []
context = etree.iterparse(
xml,
events=('end',),
tag='{http://www.opengis.net/gml/3.2}Curve',
recover=True
)
for event, curve in context:
curveId = curve.get('{http://www.opengis.net/gml/3.2}id')
print (curveId)
posLists = curve.xpath('.//gml:posList', namespaces=namespaces)
for posList in posLists:
points = posList.text.split("\n")
for point in points:
pt = point.strip().split(' ')
if len(pt) != 2:
continue
insert_buff.append({
'curve_id': curveId,
'lat': float(pt[0]),
'lng': float(pt[1])
})
if len(insert_buff) >= commit_cnt:
Curve.insert_many(insert_buff).execute()
insert_buff = []
if len(insert_buff):
Curve.insert_many(insert_buff).execute()
insert_buff = []
context = etree.iterparse(
xml,
events=('end',),
tag='{http://nlftp.mlit.go.jp/ksj/schemas/ksj-app}RailroadSection',
recover=True
)
for event, railroad in context:
railroadSectionId = railroad.get(
'{http://www.opengis.net/gml/3.2}id'
)
locationId = railroad.find(
'ksj:location',
namespaces=namespaces
).get('{http://www.w3.org/1999/xlink}href')[1:]
railwayType = railroad.find(
'ksj:railwayType', namespaces=namespaces
).text
serviceProviderType = railroad.find(
'ksj:serviceProviderType',
namespaces=namespaces
).text
railwayLineName = railroad.find(
'ksj:railwayLineName',
namespaces=namespaces
).text
operationCompany = railroad.find(
'ksj:operationCompany',
namespaces=namespaces
).text
insert_buff.append({
'gml_id': railroadSectionId,
'location': locationId,
'railway_type': railwayType,
'service_provider_type': serviceProviderType,
'railway_line_name': railwayLineName,
'operation_company': operationCompany
})
print (railroadSectionId)
if len(insert_buff) >= commit_cnt:
RailRoadSection.insert_many(insert_buff).execute()
insert_buff = []
if len(insert_buff):
RailRoadSection.insert_many(insert_buff).execute()
insert_buff = []
context = etree.iterparse(
xml,
events=('end',),
tag='{http://nlftp.mlit.go.jp/ksj/schemas/ksj-app}Station',
recover=True
)
for event, railroad in context:
stationId = railroad.get('{http://www.opengis.net/gml/3.2}id')
locationId = railroad.find(
'ksj:location', namespaces=namespaces
).get('{http://www.w3.org/1999/xlink}href')[1:]
railwayType = railroad.find(
'ksj:railwayType',
namespaces=namespaces
).text
serviceProviderType = railroad.find(
'ksj:serviceProviderType',
namespaces=namespaces
).text
railwayLineName = railroad.find(
'ksj:railwayLineName',
namespaces=namespaces
).text
operationCompany = railroad.find(
'ksj:operationCompany',
namespaces=namespaces
).text
stationName = railroad.find(
'ksj:stationName',
namespaces=namespaces
).text
railroadSection = railroad.find(
'ksj:railroadSection',
namespaces=namespaces
).get('{http://www.w3.org/1999/xlink}href')[1:]
print (stationId)
insert_buff.append({
'gml_id': stationId,
'location': locationId,
'railway_type': railwayType,
'service_provider_type': serviceProviderType,
'railway_line_name': railwayLineName,
'operation_company': operationCompany,
'station_name': stationName,
'railroad_section': RailRoadSection.get(
RailRoadSection.gml_id == railroadSection
)
})
if len(insert_buff) >= commit_cnt:
Station.insert_many(insert_buff).execute()
insert_buff = []
if len(insert_buff):
Station.insert_many(insert_buff).execute()
Einmal in der Datenbank gespeichert, ist der Rest einfach zu bedienen.
Die Punkte, die mir beim Umgang mit nationalen numerischen Landinformationen (Eisenbahndaten) aufgefallen sind, sind nachstehend beschrieben.
・ Es ist nicht möglich, nur den Routennamen einzugrenzen. Zum Beispiel kann im Fall von "Linie 1" "Yokohama City" es halten oder "Chiba Monorail" kann es halten. Daher ist es notwendig, nach "Betreiber" und "Routenname" einzugrenzen.
・ Der Name kann sich von dem Namen unterscheiden, den Sie immer verwenden. JR East wurde zur East Japan Passenger Railway und Tokyo Metro zur Tokyo Subway.
・ Die Route kann sich von der Route unterscheiden, die Sie immer verwenden. In einer normalen Routenkarte ist beispielsweise "Tokio" in "Chuo Line" enthalten. "Tokio" ist jedoch nicht als nationale Landnummerninformation in der "Chuo-Linie" enthalten. "Tokyo" - "Kanda" gilt als "Tohoku Line". Dies scheint darauf zurückzuführen zu sein, dass der Abschnitt zwischen der Tokyo Station und der Kanda Station auf einer speziellen Linie verläuft, die auf der Tohoku Main Line verlegt ist.
Recommended Posts