Jintrick.netagenda2003年02月アーカイブ → 2003年02月19日

複数の文書を効率的に検証(XML Schema / MSXML)

単一のXML Schema文書で複数のXML文書を検証するための実用化に向けて動いてみました。

一番の問題点と言えば、ルート要素にxsi:schemaLocation属性(名前空間を持っている場合)あるいはxsi:noNamespaceSchemaLocation属性(名前空間を持っていない場合)を記述して、スキーマ文書へのリンクを作成しなければならない点です。より正確には、それらの属性を記述することによってパーサがスキーマ文書を必ず読み込んでしまうのが問題です。

パーサが賢ければ問題にはならない筈ですが、残念ながらMSXML君は自動でキャッシュを利用してくれることは無いようです。それどころか、standalone="yes"と宣言しても、あるいは、validateOnParse = false; と設定しても、ご丁寧に長大なスキーマ文書を読み込んでしまうようです。

どうしようもないので、先に挙げたxsi:schemaLocation属性やxsi:noNamespaceSchemaLocation属性を記述せずに、任意のスキーマ文書でそのXML文書を検証する方法を探ってみました。

XMLSchemaCacheオブジェクト

MSXML4にはXMLSchemaCacheというものが用意されていました。

1. キャッシュの作成

まずこのようにしてオブジェクトを作成します。

var cache = new ActiveXObject("Msxml2.XMLSchemaCache.4.0");

ここまでは良いのですが、私がやりたいのは任意のスキーマ文書をこの「キャッシュ」に含めることです。従って、参照先の例に挙げられているaddCollectionメソッドは使えません(結局例の長ったらしい属性を記述しなければならない)。addメソッドが使えます。

cache.add('', 'C:\\schema\\hub-jtr.xsd');

第一引数に名前空間URI(string)、第二引数にスキーマ文書のパス(string)を指定します。名前空間を持たない場合、第一引数は空文字列でOKなようです。

2. キャッシュの関連付け

で、このキャッシュを検証したいXML文書に関連付けるにはどうするかというと、DOMDocumentオブジェクトのschemasプロパティにこのキャッシュを「代入」すれば良いらしいです。……甚だ不正確な表現です。正しくは、「IXMLDOMDocument2オブジェクトのschemasプロパティを、このキャッシュへの参照に設定する」と書けば良いのでしょうか。ややこしい表現です。

var doc = new ActiveXObject('MSXML2.DOMDocument.4.0');
doc.async = false;
doc.load('C:\\Documents\\index.xml');
doc.schemas = cache;

3. 検証

IXMLDOMDocument2オブジェクトのvalidateメソッドで実際に検証できます。このメソッドはIXMLDOMParseErrorオブジェクトを返却しますが、loadメソッドが完了した時点で作成されるIXMLDOMParseErrorオブジェクト(この例ではdoc.parseErrorで参照可能)が更新されるわけではない点に注意が必要かもしれません。私はここで引っかかりました。

var err = doc.validate();
if(err.errorCode !== 0)
alert(err.line + ' : ' + err.reason);

これで、「118 : DTDまたはスキーマによると要素の内容が正しくありません」なんてなメッセージを得られるわけです。

面倒くさいので、自作のgetErrorメソッドの引数にスキーマのキャッシュを指定する形で同様の結果を得られるよう、以上のようなプロセスを纏めてみました。しばらく使い勝手を試してみます。

閑話休題

なんで最近こんな時間(深夜3時)に更新するのかといえば、@NetHomeのFTPサーバが亀だからです。所謂「てれほたいむ」が始まった辺りから数時間、putしづらくて仕方なくなるんです。フリーのFTPソフトを使おうがDOS窓でFTP.EXEを使おうが、IEを使おうが同じです。夜な夜な巨大なバイナリデータを延々とputし続ける輩が存在するのでしょうか。勝手に想像して怒りに燃えています。


webmaster@jintrick.net
公開: 2003年02月19日
カテゴリ: Javascript ,スキーマ