lxmlのxpathで正規表現を使う方法,あるいはrrdtool-dumpのバージョン差異
PythonのXMLパーサモジュールであるlxml
のxpathにおいて,正規表現を使って検索をする方法のメモ.
いま,下のようなXMLがあるとする.
<rrd> <rra> <cf>AVERAGE</cf> <pdp_per_row>1</pdp_per_row> </rra> <rra> <cf> AVERAGE </cf> <pdp_per_row>5</pdp_per_row> </rra> <rra> <cf>MAX</cf> <pdp_per_row>1</pdp_per_row> </rra> <rra> <cf> MAX </cf> <pdp_per_row>5</pdp_per_row> </rra> </rrd>
このとき,cfの中身が"AVERAGE"あるいは" AVERAGE "(前後にスペースあり)であるツリーのpdp_per_rowの値を取得したい場合,正規表現で検索すると簡単に扱うことができる.
pdp_per_row_values = list( map( lambda e: int(e.text), tree.xpath( './rra/cf[re:match(text(), "[ ]*AVERAGE[ ]*")]/parent::node()/pdp_per_row', namespaces={"re": "http://exslt.org/regular-expressions"}))) print(pdp_per_row_values) # [1, 5]
何故こういうことをやりたかったかというと,rrdtool dump
コマンドでRRDファイルをXMLでダンプしたときに出力されるXMLがrrdtool
のバージョンによって異なるから.
rrdtool 1.3.8 ("AVERAGE"の前後にスペースあり):
$ rrdtool dump traffic.rrd | xpath '//rra/cf' Found 5 nodes: -- NODE -- <cf> AVERAGE </cf>-- NODE -- <cf> AVERAGE </cf>-- NODE -- <cf> AVERAGE </cf>-- NODE -- <cf> AVERAGE </cf>-- NODE -- <cf> AVERAGE </cf>
rrdtool 1.4.8 ("AVERAGE"の前後にスペースなし):
$ rrdtool dump traffic.rrd | xpath '//rra/cf' Found 5 nodes: -- NODE -- <cf>AVERAGE</cf>-- NODE -- <cf>AVERAGE</cf>-- NODE -- <cf>AVERAGE</cf>-- NODE -- <cf>AVERAGE</cf>-- NODE -- <cf>AVERAGE</cf>
rrdtool 1.4.8が入っている手元の環境からrrdtool 1.3.8が入っている別の環境にスクリプトを持っていったところ動かなくなったので,この罠に気付いた*1.
参考
*1:どのバージョンから挙動が変わったのかまでは調べていない