「第13回」で Pythonのlxmlモジュールを使って、デフォルト名前空間が定義されたxmlファイルでXPath使うときはどしたら良いのかしら、と考え込みました。今日は今日とて、またlxmlモジュールで、xsdスキーマファイルが複数あるときに、どうやってバリデーションをばかけたらよかでしょうかとまたまた考え込んでしまいました。
※「トホホな疑問」投稿順Indexはこちら
バリデーションの方法は、lxmlのホームページに Validation with lxml というズバリの記述があります。今までもそこに記されている方法で、何度かXML Schema(XSD)ファイルを使い、自分で生成したXMLファイルのバリーデーションを行ってみたりしてました。ただ、XMLの専門家?でもないので、数えるほどの機会でしかありません。これまでは、単一のXSDファイルばかり。
その方法を要約するならば、
STEP.1 XMLSchemaファイルを etree.parse() に食わせて取り込んでおく
STEP.2 取り込んだxsd文書を etree.XMLSchema()に与えてバリデーションを行うオブジェクトを構築しておく
STEP.3 バリデーションの対象となるXMLファイルを etree.parse()に食わせて取り込む(勿論STEP.3はSTEP.1の前にやってしまってもよい。)
STEP.4 バリデーションを行うオブジェクトのメソッド validate()にパースしたXML文書を食わせてやると、バリデーションの結果が真偽値で返る。
STEP.5 真なら、よかったよかったと終わるだけだが、偽ならどこがまずいか知りたいので、バリデーション・オブジェクトのerror_logなど調べる。
こんな感じ。そこで、STEP.1で食わせる、ナンチャラ.xsdというファイルが今まで単一のファイルであったわけです。
ところがね、今回、多少「高級な」感じだったんでしょうか、ナンチャラ.xsdのファイル、1本じゃなかったです。2本ありました。本体はかなりな分量のあるスキーマでした。もう一本、オマケのような小さなスキーマファイルも同梱されていました。多分、作成元が異なるので別々のファイルになっている模様。とりあえず、中身をよく見もせず
本体のデカイファイルに対して上記の操作をしてやればいいんじゃね
などと不埒にやってみました。結果、STEP.2でエラーを吐いて死にました。読みたくもないエラーを読めば、どうも、なにか設定が足らない感じ、それも基礎的な。そこでオマケのような小さなスキーマファイルを眺めてみると、まさに足らなかった設定の件、書かれているではありませんか。この設定を大きな本体ファイルに「とりこめれば」良いようです。どうしたら良いの?書きませんが、思いついた酷いことをいくつか試しましたが駄目でした。それで、ようやく本体の大きなXSDファイルの中身を見てみました。よく見れば
includeというタグの中に、小さなスキーマファイルの名がある
ではありませんか。
includeと書いてあるのに何でincludeしてくれないの?
今回のトホホな疑問です。Cの#includeはもとより、includeと書いてあったら、自動的にファイル読み込んでくれるもんじゃないですか。ま、ファイルが所望のパスになかったりするエラーになるのはよくあるけど。しかし、パス的には問題なさそうに見えます。そこでいろいろ探し回ったあげく、結局、lxmlのホームページの中に
という記述を見つけました。別にXSDファイルのためではないですが、XMLの中でincludeタグを働かせるための方法です。XSDもXMLなので、以下同文でありましょう。
etree.parse()
で取り込んだXML文書のツリーに対して一発 xinclude()メソッドを呼び出してやるのが lxml の流儀のようです。
tree = etree.parse(”本体XMLファイル名") tree.xinclude()
つまりSTEP.1 と STEP.2の間に、1行、引数もない xinclude()を書けば良いのでした。早速やってみました。
OKです。etree.XMLSchema()は何事もなかったように2つのXSD文書を読み込み、ほとんど一瞬で、XML文書のバリデーションも終わりました。勿論 Trueね。
なんだ、たったそれだけのことかいな。。。