2011年4月22日金曜日

XMLの検証をバージョンごとに行う

XMLの検証にはDTDかXMLスキーマを使うわけですが、
自作しているといつの間にか複数のバージョンが登場しだします。

なので読み込みの部分で、
どのバージョンなのか調べてから検証しなければなりません。

ルート要素の"version"属性にバージョン情報があるとして、
どうやれば実現できるのか考えてみます。

まず最初に言いたいのは、
XMLスキーマに統一する必要があるということです。

"Trang"というツールでDTD→XMLスキーマの変換ができるのでやっておきます。
何かエラーが出たときは…うん、ごめんなさい。

そしたら読み込み部分の処理ですね。
import java.net.URL;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.w3c.dom.Document;
public class XmlChecker {
public static void main(String[] args) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 名前空間をサポートするか
factory.setNamespaceAware(true);
// DTD検証を行うか
factory.setValidating(false);
// XMLのパース
Document document = factory.newDocumentBuilder().parse("(XMLのURI)");
// バージョン情報の取得
String version = document.getDocumentElement().getAttribute("version");
if (version.equals("1.0")) {
Schema schema = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
new URL("XMLスキーマバージョン1のURL"));
schema.newValidator().validate(new DOMSource(document));
// バージョン1の処理
} else if (version.equals("2.0")) {
Schema schema = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
new URL("XMLスキーマバージョン2のURL"));
schema.newValidator().validate(new DOMSource(document));
// バージョン2の処理
} else {
// エラー
}
} catch (Exception e) {
// エラー
}
}
}
view raw XmlChecker.java hosted with ❤ by GitHub

では軽く解説を…
まずパース時のDTD検証は無効にしています。
検証はパース後にしたいですしね。
XMLスキーマに寄せた理由もここら辺です。

で、DOMでバージョン番号を取得します。
後は各バージョンのスキーマを使って検証を行うだけっと。
例ではif文ですが、Mapとか使ってさばくのが大人の醍醐味。

あ、Schemaオブジェクトはスレッドセーフだから作りっぱなしでOKです。

XMLファイルのスキーマ情報は無視している…はずです。
もし何か悪さをしたらDocumentBuilderにEntityResolverを設定して適当に受け流してください。

これでXMLの後方互換性はバッチリ!
(…例によって誰得情報だ。)

0 件のコメント:

コメントを投稿