Pythonで名前空間付きのXMLを操作する(ElementTree)

  • 17
    Like
  • 2
    Comment
More than 1 year has passed since last update.

初めに

xml.etree.ElementTree
http://docs.python.jp/2/library/xml.etree.elementtree.html
を使って、名前空間付きのxmlを解析します。

本文ではkml(Google Earthなどに使われてるフォーマット)
http://ja.wikipedia.org/wiki/KML
をターゲットにしているが、実態はXMLなので同様に扱うとする。

対象データ

対象のKML
<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Document>
<name>Hoge</name>
 <Style id="Mapit">
 <IconStyle>
 <color>FFFFFFFF</color>
 <scale>1.0</scale>
 </IconStyle>
 </Style>
 <Style id="kml">
 <LineStyle>
 <color>FF0080FF</color>
 <width>1</width>
 </LineStyle>
 <PolyStyle>
 <color>AADDDDDD</color>
 </PolyStyle>
 </Style>
・・・
 </Document>
</kml>

一部省略しているが、とりあえずこんな形をしているKMLを対象とする。
PolyStyle->color
の値がAADDDDDDになっていますが、これを変えたいとします。

プログラムコード

XML書き換えプログラム
# -*- coding: utf-8 -*-

from xml.etree import ElementTree

#KMLファイルを読み込み
tree = ElementTree.parse("in.kml")
#namespaceを付加する
#これをしないと再書き出しの際に、全てのタグにns0:PolyStyleみたいになる
ElementTree.register_namespace('', 'http://earth.google.com/kml/2.0')

# //PolyStyle/colorを探す
for node in tree.findall(".//{http://earth.google.com/kml/2.0}PolyStyle/{http://earth.google.com/kml/2.0}color"):
    # 内容書き換え
    node.text="AA001122"

#書き出し
#3つ目の引数はtrueなら<?xml ・・?>を付加する。
tree.write("out.kml","UTF-8",True)

PolyStyle->color
の値がAA001122となって書き出されます。

解説

xml.etree.ElementTree.findallは、頭に"."がいる。
(FutureWarningとか言われる)

XPathのサブセットが扱えるらしい。
http://docs.python.jp/3/library/xml.etree.elementtree.html
(Python2に関する記事は、見つけられてない)

ここで問題なのが名前空間である。

名前空間
<kml xmlns="http://earth.google.com/kml/2.0">

がルートにあるため、それ以下は全て名前空間がかかる。

なのでパスを指定するときは、{}内で名前空間を付加し、タグを指定しなけばならない。

しかもPolyStyle->colorなので2回書かないといけない。

xpath
//{http://earth.google.com/kml/2.0}PolyStyle/{http://earth.google.com/kml/2.0}color"

(なにかいい方法が有りましたら教えて下さい。。。)

次に、register_namespace をする意味は、
writeで書きだしたXMLが

register_namespaceをしない出力
<ns0:PolyStyle>
 <ns0:color>AADDDDDD</ns0:color>
</ns0:PolyStyle>

みたいになるのを回避します。

ゆるぼ

register_namespaceしてるのでXPath指定がもっとスマート
(名前空間URIを何度も書かなくていいとか)に記述できないかなぁ。。。

参考

XPathで指定したテキストがある次の要素を取得する方法
http://qiita.com/yuki2006/items/1f96450fc744769872c5

[Python]ElementTreeのnamespaceをゴニョゴニョする
http://d.hatena.ne.jp/nullpobug/20110420/1303293319