XMLの外部リソース解決は読み込み時だけとは限らない
以前の日記で、DTD検証を行うXmlReaderの生成に関して言及した際に、外部のDTDリソースを解決するためにXmlReaderSettingsクラスのXmlResolverプロパティをセットするコード片を書いた。
//リゾルバの生成(ここではXmlUrlResolverクラスを使用) XmlResolver resolver = new XmlUrlResolver(); //設定オブジェクトの生成 XmlReaderSettings settings = new XmlReaderSettings(); settings.XmlResolver = resolver; settings.ProhibitDtd = false; settings.ValidationType = ValidationType.DTD;
XmlResolverを利用したDTDリソース解決は、XMLの読み込み時だけに必要なものだと思っていたのだが、どうもそうでは無かったようだ。
というのも、XMLを出力するために、以下のようなXMLドキュメントと、その要素を生成するコードを書いたとする。
XmlDocument doc = new XmlDocument(); XmlDocumentType docType =doc.CreateDocumentType("hoge", null, "hoge.dtd", null); doc.AppendChild(docType); XmlElement root = doc.CreateElement("root"); doc.AppendChild(root);
このコードは、"hoge.dtd"という名前の、ローカルに配置されていることを前提とするDTDを必要とする、以下のようなXMLのための要素を生成するが、
<?xml version="1.0"?> <!DOCTYPE hoge SYSTEM "hoge.dtd"> <root></root>
実際にサンプルを書いて動かしてみると、XMLでいうところのドキュメントタイプを出力する行
XmlDocumentType docType =doc.CreateDocumentType("hoge", null, "hoge.dtd", null);
を実行すると、"hoge.dtd"という名前のDTDリソースが解決できないと例外を投げるのである。(System.IO.FileNotFoundException)
従って、このコード片はXMLを読み込む時のようにXmlResolverを使用してDTDlリソースを解決するように、書き換える必要がある。
XmlDocument doc = new XmlDocument(); XmlResolver resolver = new XmlUrlResolver(); doc.XmlResolver = resolver; XmlDocumentType docType =doc.CreateDocumentType("hoge", null, "hoge.dtd", null); doc.AppendChild(docType); XmlElement root = doc.CreateElement("root"); doc.AppendChild(root);
XmlResolverとして、ここでは.NET標準のXmlUrlResolverクラスを使用しているが、これはあくまで例である。今回の例のようにローカルのファイルシステムに配置されている(相対パスを含む)DTDリソースを解決するためには、XmlResolverの派生クラスを用意したほうが良い場合がある。