読者です 読者をやめる 読者になる 読者になる

libxml2でRelaxNGを扱う

XML Python

 いつも忘れてしまい、結局ソースコードを読み返す羽目になるので、メモしておきます。

RelaxNGによるxmlDocの妥当性検証を行う

 xmlDocオブジェクトの妥当性検証を行う場合、スキーマ文書パーサー(relaxNgParserCtxt)の生成、スキーマオブジェクト(relaxNgSchema)の生成、検証コンテクストオブジェクト(relaxNgValidCtxt)の生成というステップを踏みます。
 最初にスキーマ文書パーサーを生成します。

# XMLドキュメントオブジェクトからパーサーを生成
doc = libxml2.parseFile(filename)
parser = doc.relaxNGNewDocParserCtxt()

# ファイルからパーサーを生成
parser = libxml2.relaxNGNewParserCtxt(filename)


 パーサーオブジェクトを得たならば、そこからスキーマオブジェクトを生成します。

rng = parser.relaxNGParse()


 最後に、スキーマオブジェクトを使って、対象文書の妥当性検証を行います。

# エラー・警告のコールバック関数
def error(msg, arg):
    print msg

# 対象文書を取得
doc = libxml2.parseFile(target_filename)

# 検証コンテクストオブジェクトを作る
ctxt = rng.relaxNGNewValidCtxt()

# エラー・コールバック関数を指定
ctxt.setValidityErrorHandler(
            err_func  = error,
            warn_func = error,
            arg = None
     )

# 妥当性検証を行う
ctxt.relaxNGValidateDoc(doc)

xmlTextReaderを使って、RelaxNGによる妥当性検証を行う

 xmlTextReaderを使って妥当性検証を行う場合、xmlDocと同様に、スキーマオブジェクトを自分で作って検証を行うこともできますし、もっと簡単に、RelaxNGスキーマ文書のファイル名を指定して検証を行うこともできます。検証を行うのが一回限りの場合は、後者の方が楽かもしれません。

# エラー・警告のコールバック関数
def error(reader, msg, severity, locator):
    e.error = True
    print msg

reader = libxml2.newTextReaderFilename(target)
reader.error = False

# エラー・コールバック関数を設定
reader.SetErrorHandler(error, r)

# スキーマ文書を指定
reader.RelaxNGValidate(rng_filename)
# スキーマオブジェクトを指定
# reader.RelaxNGSetSchema(rng)

# エラーor文書末まで読み込み
while not reader.error and reader.Read():
    pass

r.Close()


 xmlTextReaderを使用した場合は、必ずSetErrorHandlerでエラーハンドラを設定しなくてはなりません。このとき、プログラマは、文書が非整形式であったり、妥当ではなかったならば、xmlTextReaderの読み込みを中止する責任を負います。
 妥当性エラーと整形式エラーは区別されるので、妥当性エラーが発見された後でも、xmlTextReaderの読み込むようにすることもできますが、これは多分、スキーマ文書による妥当性検証を行うという文脈においては、正しい振る舞いではないと思われます。