静かなる名辞

pythonとプログラミングのこと


【python】lxml.etreeの使い方まとめ―pythonによるXML処理

 lxmlを使ってXMLを生成したり、パースしたりするという処理をたまに書く。そんなに頻繁にやる訳ではないので、処理の書き方を忘れてしまいがち。

 備忘録として書いておく。なお、htmlは今回扱わないので、別のサイトを見てください。

 目次

installとimport

$ pip install lxml
>>> from lxml import etree

文字列とetreeの相互変換

>>> hoge = etree.fromstring('<hoge hoge="hoge"> hoge </hoge>')
>>> s = etree.tostring(hoge, pretty_print=True).decode()
>>> print(s) # <hoge hoge="hoge"> hoge </hoge>

 せめてtostringはメソッドとして叩ければ、という気がしなくもない。あと、str(hoge)とかしてもXML文字列に変換されたりはしない。ちょっと残念。

 デフォルトでtostringがbyte列を吐いてくれるのは、python2系との互換性を重視しているのか、パフォーマンス上の理由なのか、どちらかなのだろう。

 覚えておくべきことは「etree.tostringとetree.fromstringを使えば良く(インスタンスメソッドなどではない)、to_stringやfrom_stringではない(アンダースコアは入らない)」です。これでもう迷わない。

要素を作る

# 要素を作る
>>> hoge = etree.Element("hoge")

# textを追加
>>> hoge.text = "hoge"

# attribを追加
>>> hoge.attrib["hoge"] = "hoge"

 これで上の例の hoge と等価のものができる。

tagを取得、変更

>>> hoge.tag
"hoge"
>>> hoge.tag = "fuga" # ちゃんとタグが変わる

 tagがmutableなのはちょっと恐ろしい。

子要素を追加・削除

 なぜかリスト風のインターフェイスになっている。

>>> hoge = etree.Element("hoge")
>>> hoge.append(etree.Element("fuga"))
# -> tostringすると<hoge><fuga/></hoge>
>>> hoge.remove(hoge[0])
# -> tostringすると<hoge></hoge>

親、子を取得

>>> hoge = etree.fromstring('<hoge hoge="hoge"> hoge <fuga/></hoge>')
>>> hoge.getchildren() # getchildrenは非推奨
[<Element fuga at 0x7f2ce13d0108>]

>>> list(hoge) # こちらを使うべき
[<Element fuga at 0x7f2ce13d0108>]

>>> hoge[0].getparent() # これは特に非推奨とかではない
<Element hoge at 0x7f2cdfecd948>

 

ぜんぶたどる

 pre-orderで探索してくれる。

>>> hoge = etree.fromstring('<hoge hoge="hoge"> hoge <fuga/><piyo><piyohoge/></piyo></hoge>')
>>> for x in hoge.iter():
...     print(x.tag)
... 
hoge
fuga
piyo
piyohoge
  • pre-orderの説明

 上のXMLを木構造で書くとこんな感じ。

    hoge
    /\
 fuga  piyo
        |
      piyohoge

 hogeをスタート地点にし、指を置く。左側に指を動かし、そのまま木の外側をぐるっと辿ってスタートに戻る。

 このとき指はhoge→fuga→hoge→piyo→piyohoge→hogeの順に当たる。二回も三回も同じものを見る必要はないので、最初に見たとき記録し(然るべき処理を行い)、後は同じものに当たってもスキップすることにすると、hoge→fuga→piyo→piyohogeの順番になる。

XPATHで検索

>>> hoge = etree.fromstring('<hoge hoge="hoge"> hoge <fuga/><piyo><piyohoge/></piyo></hoge>')
>>> hoge.xpath("//piyohoge")

 マッチするものが全部返るので結果はリスト。中身はエレメントのオブジェクト。

 XPATH自体についての解説はしない。いずれ気が向いたら書くかもしれないが、現時点では他のサイトをあたってください。