初めに
xml.etree.ElementTree
http://docs.python.jp/2/library/xml.etree.elementtree.html
を使って、名前空間付きのxmlを解析します。
本文ではkml(Google Earthなどに使われてるフォーマット)
http://ja.wikipedia.org/wiki/KML
をターゲットにしているが、実態はXMLなので同様に扱うとする。
対象データ
<?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になっていますが、これを変えたいとします。
プログラムコード
# -*- 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回書かないといけない。
//{http://earth.google.com/kml/2.0}PolyStyle/{http://earth.google.com/kml/2.0}color"
(なにかいい方法が有りましたら教えて下さい。。。)
次に、register_namespace をする意味は、
writeで書きだしたXMLが
<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