- blogs:
- cles::blog
PythonでXPathを使う
python xml久しぶりにPytonのプログラムをいじらないといけないことになったので、ちょっと下調べ。
Pythonは2.5からElementTree XML APIが使えるようになっていて、単純にノードを取り出すにはこんな感じで簡単にできました。
ここまでは簡単だったのですが、find()に渡せるXPathはpredicate*1がちゃんとサポートされていないようなので、複雑な条件を満たすノードは自分でトラバースする必要がありそうということでちょっと困ってしまいました。
test.xml
xml.etree.ElementTreeでpredicateを使ったときの出力
† lxmlを使ってみる
サンプルのXMLは簡単なのでいいのですが、今回扱わなければならないXMLはかなり構造が複雑なものなので、実装の負荷を考えると自分でトラバースするのは避けたいところです。
ということで色々と調べてみると、libxml2を呼び出すlxmlというライブラリがあり、こちらはちゃんとしたXPathが使えそうだということがわかりました。
Python Package Index : lxml 2.0.5
Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API.
Linuxなどを使っていて、libxml2やlibxsltなどのライブラリとコンパイル環境が既に存在している場合には、EasyInstall経由でインストールを行うのが一番簡単です。
今回はWindowsへのインストールだったので、lxmlの配布ページでで公開されている「lxml-2.0.5.win32-py2.5.exe (MS Windows installer )」を利用しました。これはコンパイル済みのバイナリなので、コンパイル環境がないWindowsにも簡単に導入できます。
ということで、上記のコードをlxmlを使ったものに書き換えたのがこちら。
predicateがきちんと評価されて結果が帰ってきています。
lxmlでpredicateを含むXPathを実行させた結果
† 最後に名前空間にはまる
とりあえず簡単なサンプルでフィージビリティが確認できたので、もうちょっと本格的なXMLを食わせてみたら、対象となるXMLにはxmlnsが指定されていてそのままでは動きませんでした。
test.xml w/ namespace
namespaceを指定しなかったとき
ちょっとベタな填り方なのでググってみたら、全く同じところではまっていたXPathでnamespaceにハマった。 - Humming Via Kitchenというエントリを参考に下記のようにソースを書き換えて事なきを得ました。
namespaceの指定をつけたとき
- *1: 述語。[expression] のような部分
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/2921
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
わたしもElementTreeのxpathでinvalid predicateが出て悶々としてこちらのサイトに辿り着いたのですが。
その後、xml.findall("//table[@id = "hoge"]")をxml.findall("//table[@id="hoge"]")のように=周辺のスペースを除去したらちゃんと処理されましたよ@.@
コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。
OpenID を使ってログインすることができます。
2 . Word で数式がグレーアウトされていて挿入できないときは(15714)
3 . アーロンチェアのポスチャーフィットを修理(12205)
4 . awk で指定した n カラム目以降を出力する(12137)
5 . 福岡銀がデマの投稿者への刑事告訴を検討中(10147)