lxmlのobjectifyを試してみたら、すごく便利でビックリした

Javaの試験勉強に集中できないbonlifeです。以下の記事を見て、なんかあったよな、と思ってlxmlのobjectifyを試してみました。

XMLPythonオブジェクトに変換するところで悩んでしまって、ちょっと奇妙な実装になっています。

id:tomoemon:20071019:p1 あたりを参考にさせていただきましたよ!

In [1]: from lxml import objectify

In [2]: import urllib2

In [3]: url = "http://api.search.yahoo.co.jp/WebSearchService/V1/webSearch?appid=YahooDemo&query=%e6%b2%96%e7%b8%84&results=2"

In [4]: root = objectify.parse(urllib2.urlopen(url)).getroot()

In [5]: root.countchildren()
Out[5]: 2

In [6]: root.getchildren()
Out[6]:
[<Element {urn:yahoo:jp:srch}Result at 10d1420>,
 <Element {urn:yahoo:jp:srch}Result at 114ed50>]

In [7]: for i in root.Result[0].getchildren():
  ....:     print "%s\t%s" % (i.tag, i.text)
  ....:
  ....:
{urn:yahoo:jp:srch}Title        沖縄情報IMA
{urn:yahoo:jp:srch}Summary      沖縄の気候、交通、観光、宿泊、遊び等の情報。ホテル、ビーチのオススメランク一覧等。
{urn:yahoo:jp:srch}Url  http://www.okinawainfo.net/
{urn:yahoo:jp:srch}ClickUrl     http://wrs.search.yahoo.co.jp/l=WS1/R=1/IPC=jp/H=1//SIG=11f2ieaos/EXP=1204973303/*-http%3A//www.okinawainfo.net/
{urn:yahoo:jp:srch}ModificationDate     1204729200
{urn:yahoo:jp:srch}MimeType     text/html
{urn:yahoo:jp:srch}Cache        None

In [8]: root.Result.Cache.Size
Out[8]: 13812

なんかすごく便利っぽい!ドットでのアクセス最高!ただ、ちょっとイメージと違うところも…。

In [9]: type(root.Result.ModificationDate)
Out[9]: <type 'lxml.objectify.IntElement'>

Yahoo!が定義しているXML Schema(こちら)に従うと、コイツは type="xs:string" ってなってるんだけどなぁ…。
明示的にXML Schemaを指定すれば上手く行くかな、と思って試してみたところ…

from lxml import etree, objectify
import urllib2

url = "http://api.search.yahoo.co.jp/WebSearchService/V1/webSearch?appid=YahooDemo&query=%e6%b2%96%e7%b8%84&results=2"
xsd = "http://api.search.yahoo.co.jp/WebSearchService/V1/WebSearchResponse.xsd"
schema = etree.XMLSchema(file=urllib2.urlopen(xsd))
parser = objectify.makeparser(schema=schema)
root = objectify.parse(urllib2.urlopen(url),parser=parser).getroot()

print type(root.Result.ModificationDate)

の結果が

>yahoo_api_lxml_text.py
<type 'lxml.objectify.IntElement'>

ですってよ。ううむ。ちょっとイミフです。でも、YAPIのソース読んでも、types.IntType にしてますね。

class WebSearchResponse(SearchResponse):
    
    form = { 'ResultSet':
             [ {'Result': { 'Title': types.StringType,
                            'Summary' : types.StringType,
                            'Url' : types.StringType,
                            'ClickUrl' : types.StringType,
                            'MimeType' : types.StringType,
                            'ModificationDate': types.IntType,
                            'Cache' : types.StringType,
                            }
                }
               ]
             }

そもそもこの項目の意味は「ページが最後に修正された日付です。UNIXタイムスタンプフォーマットです。」ってことらしいので、types.IntType で正解なのかな。XML Schema が間違ってる?
謎が謎を呼ぶので、今日はこのあたりにしておきます。言いたいことは2点。

  • 外部モジュールに依存して楽しても良い気がする (lxml万歳!)
  • XML Schemaまわりが謎過ぎる

ということで、lxmlでXML Schemaあたりをゴニョゴニョするのに詳しい人、ヘルプミーです!