Tag/XPath
XPathでnamespaceにハマった。
lxml で XPath 使ってる時に namespace でハマったのでメモ。 ありがちなところでハマった。 恥さらしの為にもメモりますです。
どんなところでハマったかと言うと、 例えばこんな感じの test.xml なXMLがありまして、
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://example.com/hoge/1.0">
<child>
<type>1</type>
<name>hoge</name>
</child>
<child>
<type>1</type>
<name>hige</name>
</child>
<child>
<type>0</type>
<name>hage</name>
</child>
</root>
これを lxml でパースしてやろうとした訳です。 で、何も考えずにこんな事したら中身が取れなかった。
>>> from lxml import etree
>>> xml = etree.parse(open('test.xml', 'r'), parser=etree.XMLParser())
>>> xml
<etree._ElementTree object at 0x1290940> # ココは取れてる。
>>> root = xml.getroot()
>>> root
<Element {http://example.com/hoge/1.0}root at 1236c60> # ココもOK。
>>> # ココからが問題。
>>> root.xpath('./child')
[] # 空っぽ?
仕事中に色々試してみるも、 結局 namespace の指定の仕方が解らず撃沈。 が、家に帰ってきてから本家のドキュメント見てみると、 あっさりやり方が書いてあった。 どうやら xpath の第2引数で、 namespace を指定出来るらしい。
>>> root.xpath('./n:child', namespaces={'n':'http://example.com/hoge/1.0'})
[<Element {http://example.com/hoge/1.0}child at 1292fc0>,
<Element {http://example.com/hoge/1.0}child at 1292ea0>,
<Element {http://example.com/hoge/1.0}child at 1297030>]
>>>
>>> root.xpath('./n:child/n:name/text()', namespaces={'n':'http://example.com/hoge/1.0'})
['hoge', 'hige', 'hage']
とりあえず、めでたく XPath での問い合わせが出来た ![]()
それにしても恥ずかしいな。この凡ミス。 なんで本家のドキュメントを読もうと思わなかったんだろ? そこが本当に不思議。
- Posted at:
- 2007/12/25 23:46:20
- 4 Comments
- 1 TrackBack
- Trackback:
- http://humming.via-kitchen.com/2007/12/25/namespace-trap-on-xpath/trackback/
JavaScript-XPathを触ってみたよ。
個人的に XPath がトレンドってのもあって、 JavaScript-XPath を使ってみたよ。
amachang さんの こちらのエントリー で jQuery のバインディングが公開された事を知って、 XPath for jQuery も使ってちょくちょく触ってみたけど、 全く意識する事無く使えて物凄くいい感じ。
ダウンロードはココからしてきたっす。
- JavaScript-XPath
- JavaScript-XPath - CodeRepos::Share - Trac
- XPath for jQuery
- JavaScript-XPath/bindings/jQuery - CodeRepos::Share - Trac
まだまだ大した XPath を書けないので、 キョーレツなテストとかは出来ないけど、 個人的には end() が併用出来るのがめちゃくちゃ嬉しい。 end() って jQuery の重要な機能の1つなので、 これが併用出来るかどうか?でかなり印象が変わってくる(と思う)。
これから常用プラグインとして使っていきそうな勢いなので、 気付いた事とかフィードバックしていけたら良いなぁ。 まずは lxml と JavaScript-XPath で XPath と仲良くならなくちゃね。
- Posted at:
- 2007/11/20 01:53:56
- 0 Comments
- 0 TrackBacks
- Tags:
- JavaScript
- jQuery
- XPath
- Trackback:
- http://humming.via-kitchen.com/2007/11/20/tried-using-javascript-xpath/trackback/
lxmlを試してみたよ。(その2)
前回 に続いて lxml を使って色々やってみたよ。
テスト用のファイルを書くのもメンドクサイので、 このサイトのカテゴリーリストで遊んでみる事にした。
>>> from httplib import HTTPConnection
>>> from lxml import etree
>>> # とりあえずHTMLを取ってくる。
>>> conn = HTTPConnection('humming.via-kitchen.com')
>>> conn.request('GET', '/')
>>> # レスポンスをパース。
>>> html = etree.parse(conn.getresponse(), parser=etree.HTMLParser()).getroot()
ここから lxml でサクサク遊んでみる。
>>> # カテゴリーリストを取ってくる。
>>> html.xpath('//div[@id="subContent"]/ul[@class="cloudList"]')
[<Element ul at 2489f90>]
>>> ul = html.xpath('//div[@id="subContent"]/ul[@class="cloudList"]')[0]
>>> # リストのリンクを取ってくる。
>>> ul.xpath('./li/a')
[<Element a at 2489fc0>, <Element a at 248f720>, ..., <Element a at 248fe70>]
>>> # リンクのテキストを取ってくる。
>>> ul.xpath('./li/a/text()')
['ActionScript', 'AIR', ..., 'vim']
テキストを取りたい場合は text() 、 ならアトリビュートはどうやって取るんだろう?と疑問が。
で、色々調べたり試したりした結果、 @ATTRIBUTE で取れるらしいっす。
>>> # hrefを取ってくる。
>>> ul.xpath('./li/a/@href')
['/weblog/tag/actionscript/', '/weblog/tag/air/', ..., '/weblog/tag/vim/']
>>> # classを取ってくる。
>>> ul.xpath('./li/a/@class')
['rank9', 'rank2', ..., 'rank2', 'rank8']
これが分かると一気に使い勝手が良くなってきた! もうね、 lxml 素敵。ってか XPath 素敵。
- Posted at:
- 2007/11/14 03:00:24
- 0 Comments
- 0 TrackBacks
- Trackback:
- http://humming.via-kitchen.com/2007/11/14/tried-using-lxml-part2/trackback/
lxmlを試してみたよ。
遅ればせながら lxml を試してみたよ。コレ、かなり便利っすなぁ。
インストールは easy_install でするのが簡単で良いと思う。 yolk で検索してみると、2.0alphaとかも出てきたので、 今回はバージョンを指定してインストールしてみた。
$ sudo easy_install lxml==1.3.6
テスト用にこんな感じのXMLを用意して、 test.xml とかで保存。
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<id>1</id>
<name>hoge</name>
<type>word</type>
</item>
<item>
<id>2</id>
<name>hige</name>
<type>word</type>
</item>
<item>
<id>3</id>
<name>hage</name>
<type>image</type>
</item>
</items>
lxml を使って遊んでみる。
>>> from lxml import etree
>>> xml = etree.parse(open('test.xml', 'r'), parser=etree.XMLParser())
>>> xml
<etree._ElementTree object at 0x7406c0>
>>> # ルートノード(items)を取ってくる。
>>> items = xml.getroot()
>>> items
<Element items at 7417b0>
>>> # 子要素(item)を取ってくる。
>>> items.getchildren()
[<Element item at 7417e0>, <Element item at 7418a0>, <Element item at 741840>]
>>> # XPathで子要素(item)を取ってくる。
>>> items.xpath('./item')
[<Element item at 7417e0>, <Element item at 7418a0>, <Element item at 741840>]
>>> # XPathで孫要素(name)のテキストを取ってくる。
>>> items.xpath('./item/name/text()')
['hoge', 'hige', 'hage']
文字列から直接パースする場合は、 etree.fromstring なメソッドを使うと良いらしい。
>>> text = open('test.xml', 'r').read()
>>> items = etree.fromstring(text, parser=etree.XMLParser())
>>> items
<Element items at 7418a0>
文字列からのパースだと、 getroot しなくても直接ルートノードが返ってくる。
逆に、ノードを文字列にしたい場合だと、 etree.tostring なメソッドを使うと良いみたい。
>>> # itemノードの1個目を文字列に。
>>> etree.tostring(items.xpath('./item')[0])
<item>
<id>1</id>
<name>hoge</name>
<type>word</type>
</item>
>>> # 最後のitemノードに含まれるnameノードを文字列に。
>>> etree.tostring(items.xpath('./item[position()=last()]/name')[0])
<name>hage</name>
色々簡単に使えていい感じ。 XPath もちゃんと覚えないとなぁ。 HTMLを扱うときは、 parser を etree.HTMLParser にしてあげれば良いよ。
- Posted at:
- 2007/11/11 19:48:07
- 2 Comments
- 1 TrackBack
- Trackback:
- http://humming.via-kitchen.com/2007/11/11/tried-using-lxml/trackback/