PythonでXMLを読む話が舞い込んだので調査をしました。
扱っているXMLタグの構成がnamespace:tag_nameの形式のものがあり、
namespace付きのタグがうまく検索できなかったため、コードをまとめました。
サンプルコードのURLを加えてなかったので追加しました。
サンプルコード
phpならsimplexml_load_stringで読み込めます。
phpの場合は namespace_tag_nameに変換されるので気にせずノードの検索ができます。
pythonだと事前にnamespaceを配列に格納し、find関数を実行するときにnamespaceの配列を渡してあげないと検索できません。
そんなわけでnamespaceのあるXMLの読み込み方法
まずは読み込むXMLの内容を抜粋します。こんなタグ構成です。
MESH03622.gml
<?xml version="1.0" encoding="UTF-8"?>
<gml:FeatureCollection xmlns:fme="http://www.safe.com/gml/fme" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:gml="http://www.opengis.net/gml" xsi:schemaLocation="http://www.safe.com/gml/fme MESH03622.xsd">
<gml:boundedBy>
<gml:Envelope srsName="EPSG:4612" srsDimension="2">
<gml:lowerCorner>24.4333333329177 122.924999999934</gml:lowerCorner>
<gml:upperCorner>24.4833333336014 123.000000000218</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<gml:featureMember>
<fme:MESH03622 gml:id="id060c8300-20cf-4750-b6a6-6b9730bc8fb3">
<fme:FID>0</fme:FID>
<fme:KEN_ID>47</fme:KEN_ID>
<fme:KEY_CODE>36225734</fme:KEY_CODE>
<fme:MESH1_ID>3622</fme:MESH1_ID>
<fme:MESH2_ID>57</fme:MESH2_ID>
<fme:MESH3_ID>34</fme:MESH3_ID>
<gml:surfaceProperty>
<gml:Surface srsName="EPSG:4612" srsDimension="2">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>24.4416666664184 122.925000000467 24.4500000000747 122.924999999934 24.4500000002353 122.937499999765 24.4416666669395 122.937499999636 24.4416666664184 122.925000000467</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
</gml:surfaceProperty>
</fme:MESH03622>
</gml:featureMember>
そのXMLを読み込むためのPythonスクリプト
ReadXMLSample.py
from pprint import pprint
import os
import xml.etree.ElementTree as ET
# XMLに指定されているNameSpaceをそれぞれ登録する
# xmlns:fme="http://www.safe.com/gml/fme" これは 'fme' : 'http://www.safe.com/gml/fme' となる
ns = {'gml': 'http://www.opengis.net/gml', 'fme': 'http://www.safe.com/gml/fme', 'xlink': 'http://www.w3.org/1999/xlink'}
tree = ET.parse(fileName)
root = tree.getroot()
# AtrributeのsrsNameを取得する
pprint ("envelope = " + root.find('gml:boundedBy/gml:Envelope', ns).attrib['srsName'].strip())
# gml:featureMember以下を取得したい
fmeNodes = root.findall('gml:featureMember', ns)
records = []
for itemNode in fmeNodes:
# ルート以下のnodeの値が欲しい場合、rootからのパスを記述することで値が取得できる
# findするときに namespaceの配列を指定するのを忘れずに!
pprint ("KEN_ID = " + itemNode.find('fme:MESH03622/fme:KEN_ID', ns).text.strip())
# 現在のitemNodeを基準に相対パス指定で取得可能
pprint ("KEN_ID = " + itemNode.find('.//fme:KEN_ID', ns).text.strip())
# pointlistが取得したい場合も同様でパスを記述する
pprint ("posList = " + itemNode.find('fme:MESH03622/gml:surfaceProperty/gml:Surface/gml:patches/gml:PolygonPatch/gml:exterior/gml:LinearRing/gml:posList', ns).text.strip())
# データが流れ過ぎないように便宜上break
break
読み込み方はいくつか方法がありますが、読み込んだタグからの相対パスまたは絶対パスで指定すればいい。
そういうふうに考えておけばいいかなと。