LoginSignup
12
10

More than 5 years have passed since last update.

PythonでNamespace指定のXMLを読む

Last updated at Posted at 2016-07-26

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

読み込み方はいくつか方法がありますが、読み込んだタグからの相対パスまたは絶対パスで指定すればいい。
そういうふうに考えておけばいいかなと。

12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10