Python 2.6/2.7のxmlrpclibでxml.parsers.expat.ExpatErrorが出た場合の対処
Python 2.6系および2/7系のxmlrpclibで、サーバーからはどう見ても正しいXMLが返ってきているはずなのにxml.parsers.expat.ExpatErrorが出た場合の対処方法メモ。
xmlrpclibでは、サーバーから受け取ったXMLデータを一定サイズごとに分割してXMLパーサーに投入する、という処理を行っている。このときXMLパーサーにExpatを使っていると、受け取ったデータが分割される位置によっては、不正なXMLと認識されて以下のようにエラーになる模様(DebianのPython 2.6.6とMac OS XのPython 2.7.2で確認)。Expatを使わないようにするとこの問題は発生しない。
File "/Users/hylom/repos/anpanel/myxmlrpclib.py", line 559, in feed self._parser.Parse(data, 0) xml.parsers.expat.ExpatError: not well-formed (invalid token): line 30, column 114
たぶん挙動的にExpatのバグのようだが、それを修正する気力もなかったので、とりあえずxmlrpclibでExpatを使わないようにすることで対処。たぶんパース速度は低下すると思われるが。具体的には、xmlrpclibをimportしたのち、XMLパーサーを取得するxmlrpclib.getparser関数を以下のようにして置き換える。
import xmlrpclib # xmlrpclib's ExpatParser has bug, so do not use org_getparser = xmlrpclib.getparser def mygetparser(use_datetime=0): (p, t) = org_getparser(use_datetime) # if parser is ExpatParser, replace to SlowParser if isinstance(p, xmlrpclib.ExpatParser): p = xmlrpclib.SlowParser(p._target) return (p, t) xmlrpclib.getparser = mygetparser
ここでは、getparser関数の戻り値がExpatParserクラスのインスタンスだった場合、SlowParserクラスのインスタンスに置き換えるという処理をやっている。当然ながらかなりのdirty hackなので利用はおすすめしない。