Help us understand the problem. What is going on with this article?

PythonでNamespace指定のXMLを読む

More than 3 years have passed since last update.

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

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

Syn256
センサーとか機械学習とか、興味が湧いたらとりあえずプログラム書いてみて遊んでいます。 仕事では LAPP中心で扱っています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away