突然ですがサンプルを。DOM Level 3 Core、Load and Saveの仕様書はおさえておく必要があります。
import DOMImplementationSource as src
impl = src.getDOMImplementation("LS 3.0 MS")
parser = impl.createLSParser(1, "http://relaxng.org/ns/structure/1.0")
config = parser.domConfig
config.setParameter("schema-location", "xhtml1-transitional.rng")
config.setParameter("xml-catalog", "mycatalog.xml")
config.setParameter("validate", True)
doc = parser.parseURI("test.xhtml")
doc.xpathNSMap["xht"] = "http://www.w3.org/1999/xhtml"
nl = doc.selectNodes(
"descendant::xht:*/@*[name() = 'src' or name() = 'href']")
for att in nl:
print att.value
config.setParameter("validate", False)
styleDoc = parser.parseURI("xhtml_to_rss.xsl")
xslt = impl.createXSLTStylesheet(styleDoc)
resultDoc = xslt.transformDocument(doc, None)
serializer = impl.createLSSerializer()
serializer.writeToURI(resultDoc, "test.rss")
libxml2modを使って、W3C DOM Level 3 Core、LS、XPath等 の実装を作ってみよう……としました。わらい。
Python 2.3、libxml2(The XML C parser and toolkit of Gnome)が必要です。
インストールは適当にやってください。良く分からない場合おっかないから止めておいてください。
わざわざ苦労してこんな事をするからには、それなりに訳があります。
DOM Level 3ではブートストラッピング(実装の取得)が仕様に盛り込まれました。今まで全コード共通のブートストラッピングに関しては自分で勝手にいろいろやっていたので、このインターフェイス(DOMImplementationSource)で書き直そうと思ったのがそもそものきっかけです。
バグは至る所にあります。特にメモリリークには十分に気を付ける必要があります。
先のサンプルコードの場合、関数内に入れて呼び出す形にすると、各変数の参照カウントが減って、libxml2のfree系のメソッド(freeDoc()等)が自動で呼ばれ(るように工夫してい)ます。とはいえ必ず次のようなコードで確認する必要があります。
import libxml2, libxslt
libxml2.debugMemory(1)
コードを記述
libxml2.cleanupParser()
libxslt.cleanup()
if libxml2.debugMemory(1) == 0:
print "No memory leak"
else:
print "Memory leak %d bytes" % (libxml2.debugMemory(1))
libxml2.dumpMemory()
メモリを解放するメソッドと引数に与えるPyObjectを参照している属性を列挙:
XPathを用いたノードリストの取得とXSLTによる変換に関しては、独自拡張インターフェイスにしました。feature名「MS」で実装を取得します。メソッドやアトリビュートの詳細はインタープリタでhelp()か何かしてください。
libxml2のデータモデルが無茶なので、実体参照は置き換えます。実体参照大好きっ子は勘弁してください。因みに私は実体参照が大嫌いです。
libxml2modを利用しているので、libxml2で出来ないことは、出来ません。出来ることも、出来ない場合があります。そのような場合はlibxml2のAPIを使用してください。
libxml2modが返したPyObjectにDOMのインターフェイスを被せてノードを生成する為、ノードの同一性の確認が苦手です。isSameNodeメソッドが唯一の手段ですが、かなり非効率になっています。
NodeList、NamedNodeMapを「生きた」状態に保つ為、内部的にXPathを使用しています(手抜き)(因みに、参考にする為ソースコードを読んでみたところ、xml.dom.minidomモジュールのそれらは「死んで」いました)。そのため、ノードを検索して処理といった作業にはXmlTextReaderインターフェイスを使った方が「省エネ」です。このインターフェイスはMSモジュールで定義しており「工場」DOMImplementationMS の createXmlTextReaderメソッドでオブジェクトを作成可能です。XmlTextReaderインターフェイスについてはLibxml2 XmlTextReader Interface tutorial 参照。
DOMConfigurationの各パラメータには、殆ど対応していません。値を変更可能かどうかはcanSetParameterメソッドで確認してください。以下変更できる主なパラメタ: