XML/TEIを python の lxml で処理する際のハマりどころと解決策

スポンサーリンク

pythonのlxmlでXML/TEIを処理する際のハマりどころと解決策

TEI 準拠の XML を python で処理する際にいくつかハマりどころがあったので、備忘録の意もかねてその解決策を知見としてまとめておこうと思います。なお python で XML を処理する方法はこちらのページにサンプルコードを掲載してあります。合わせて参照ください。

python では xml ファイルを処理するために xml ライブラリが標準で搭載されています。
しかし、今回は lxml というサードパーティーのライブラリを用います。lxml は裏の処理がおそらく C 言語で書かれており処理が高速なのと、xml ライブラリにはない機能が多数搭載されているためです。

xml:id 属性をもつ xml ファイルをパースする際にエラーを返す

xml ファイルを処理する際には lxml の etree を主に使用します。
etree を用いた基本的なファイルのパース手段は以下の通りです。

from lxml import etree

file_path = "" #読み込みたい xml ファイルの URL xml_string = etree.parse(file_path)

しかし、TEI 準拠のファイルをパースする際、上記の方法ではエラーが生じることがあります。「xml:id」のように名前にコロンが入っている属性が存在する場合です。etree では NCName の命名規則に従っているため、属性名にコロンが使えない規定となっているからです。

これを解決する方法として複数通りありそうですが、一番手っ取り早いのは recover=True の変数を持ったパーサーを用いてパースする方法です。

from lxml import etree

file_path = "" #読み込みたい xml ファイルの URL parser = etree.XMLParser(recover=True) # NCName エラーを回避するため xml_string = etree.parse(file_path, parser)

recover=True を指定した etree.XMLParser は主に「壊れた」xml ファイルをパースする際に用いられるものだそうです。ここではコロンの付いた属性名 (xml:id など) を持つ xml ファイルをある種の「壊れた」xml と捉え、それでも無理やりパースするという形を取っています。

方法としてスマートか否かはさておき、一応これでも NCName エラーを回避することができます。

lxml.etree での XPath の指定方法

TEI のテキストは以下のように "http://www.tei-c.org/ns/1.0" のネームスペースに従っていることが多いかと思います。

<TEI xmlns="http://www.tei-c.org/ns/1.0">
...
</TEI>

XPath を指定する際、xml ライブラリを用いればある程度無茶な書き方でもちゃんと認識されてしまいますが、lxml では正規の書き方を踏まえないとエラーが返ってきます。

# lxml ライブラリを用いた XPath の指定方法
path = xml_string.xpath("./tei:text/tei:body/*", namespaces={"tei": "http://www.tei-c.org/ns/1.0", "xml": "http://www.w3.org/XML/1998/namespace"})

要はネームスペースを辞書型で指定しつつ、パスを指定しましょうということですね。