Avec le service national de téléchargement d'informations numériques foncières, vous pouvez obtenir des données gérées par le ministère des Terres, des Infrastructures, des Transports et du Tourisme. Cette fois, je vais tracer les coordonnées sur Google Map en utilisant les données ferroviaires.
** démo: ** http://needtec.sakura.ne.jp/railway_location/railway
GIT: https://github.com/mima3/railway_location
Les données ferroviaires peuvent être téléchargées à partir de la page suivante.
** Information numérique terrestre nationale Données ferroviaires ** http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N02-v2_2.html
Veuillez vous référer à ce qui suit pour l'utilisation de XML dans le fichier téléchargé. http://nlftp.mlit.go.jp/ksj/gml/product_spec/KS-PS-N02-v2_1.pdf
En termes simples, les données ferroviaires contiennent des informations qui montrent la forme de la ligne et des informations sur la gare. Ici, les éléments importants sont: ・ Gml: informations sur la courbe de courbe ・ Ksj: railroadSection Informations sur la section ferroviaire ・ Ksj: Informations sur la gare
Les informations de coordonnées sont stockées dans Curve. Le lien vers Curve est stocké dans l'élément d'emplacement de railroadSection et Station.
Comme il est difficile de gérer une grande quantité de données en XML, elles sont temporairement stockées dans une base de données relationnelle.
À ce stade, un XML de grande taille est analysé, mais si le fichier XML entier est une fois stocké en mémoire et analysé, l'utilisation de la mémoire augmentera considérablement et il ne sera pas possible de le traiter. Par conséquent, utilisez lxml.etree.iterparse pour traiter de manière séquentielle.
Cependant, lors de l'analyse de N02-XX.xml avec lxml.etree.itreparse, une erreur se produit. C'est parce qu'il y a des lignes dans le XML qui ressemblent à ceci:
xmlns:schemaLocation="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app KsjAppSchema-N02-v2_0.xsd">
lxml considère l'URI spécifié ici comme un URI non valide et génère une erreur. Pour éviter cela, il est nécessaire de spécifier recover = True lors de l'analyse de XML dans lxml. http://stackoverflow.com/questions/18692965/how-do-i-skip-validating-the-uri-in-lxml
** Solution de contournement: **
context = etree.iterparse(
xml,
events=('end',),
tag='{http://www.opengis.net/gml/3.2}Curve',
recover=True
)
Dans iterparse, cet argument a été introduit après lxml == 3.4.1, vous devez donc spécifier la version pour installer lxml.
easy_install lxml==3.4.1
Sur la base de ce qui précède, le processus d'importation du XML des données ferroviaires dans la base de données est le suivant.
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):
"""
Base de classe de modèle
"""
class Meta:
database = database_proxy
class Curve(BaseModel):
"""
Modèle d'information de courbe
"""
curve_id = CharField(index=True, unique=False)
lat = DoubleField()
lng = DoubleField()
class RailRoadSection(BaseModel):
"""
Modèle d'information de section de chemin de fer
"""
gml_id = CharField(primary_key=True)
#Étant donné que la clé externe doit avoir une clé primaire ou une contrainte unique,
#Elle ne peut pas être spécifiée comme clé externe pour plusieurs données.
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):
"""
Modèle d'information de la station
"""
gml_id = CharField(primary_key=True)
#Étant donné que la clé externe doit avoir une clé primaire ou une contrainte unique,
#Elle ne peut pas être spécifiée comme clé externe pour plusieurs données.
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):
"""
Configuration de la base de données
@param path Chemin de la base de données
"""
global database
database = SqliteDatabase(path)
database_proxy.initialize(database)
database.create_tables([Curve, RailRoadSection, Station], True)
def import_railway(xml):
"""
National Land Numerical Institute N02-XX.Importer des informations d'itinéraire et de station à partir de XML
TODO:
Importation inefficace de clés externes
@chemin XML param xml
"""
commit_cnt = 2000 #INSÉRER chaque numéro spécifié ici
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()
Une fois stocké dans la base de données, le reste est facile à utiliser.
Les points que j'ai remarqués lors du traitement des informations numériques foncières nationales (données ferroviaires) sont décrits ci-dessous.
・ Il n'est pas possible de restreindre uniquement le nom de l'itinéraire. Par exemple, dans le cas de la «Ligne 1», «Yokohama City» peut la retenir ou «Chiba Monorail» peut la contenir. Par conséquent, il est nécessaire de préciser par «société exploitante» et «nom de l'itinéraire».
・ Le nom peut être différent de celui que vous utilisez toujours. JR East est devenu le chemin de fer de passagers de l'est du Japon et le métro de Tokyo est devenu le métro de Tokyo.
・ L'itinéraire peut être différent de celui que vous utilisez toujours. Par exemple, dans une carte d'itinéraire normale, "Tokyo" est inclus dans "Chuo Line". Cependant, "Tokyo" n'est pas inclus dans la "Ligne Chuo" en tant qu'information numérique sur les terres nationales. «Tokyo» - «Kanda» est considéré comme «Tohoku Line». Il semble que cela soit dû au fait que la section entre la gare de Tokyo et la gare de Kanda fonctionne sur une ligne dédiée posée sur la ligne principale de Tohoku.
Recommended Posts