iPEXコラム:【応用】DTD(Document Type Definition)の使用
この文書では、サンプルプログラムvalidator.exeのソースコードを用い、XML文書のパースを実行する際にDTDを用いて検証を行う方法について紹介します。
| 作成するプログラム | validator.exe |
|---|---|
| リンク ソースコード | validator.zip |
DTDについて
XMLには整形式と検証済みの文書があります。整形式のXML文書は、XMLの構文規則に準拠しているものです。検証済みのXML文書は、特定の論理構造に準拠していることが保証されているものです。検証済みのXML文書が準拠するべき論理構造を定義するものがDTDです。つまり、DTDは多数の要素名、要素間の可能な組み合わせ、各要素タイプで使用可能な属性などの一覧です。DTDはXML文書で使用される構文とは異なる構文を使用します。
iPEXはDTDにアクセスして、XML文書がDTDに従っているかどうかを検証することができます。
iPEXでは、XML文書を読み込む際にDTDによる検証を行うことができます。また、その後も特定のドキュメントノードに対して検証を行うことができます。ただし、読み込み後の検証では一部の妥当性が検証されません。
このサンプルではXML文書を読み込む際に、DTDにアクセスして検証を行う方法について解説します。
サンプルDTDファイル、XMLファイル
次に書籍リストを格納するXML文書の論理構造を定義するDTDファイル(booklist.dtd)の内容を示します。
| ELEMENT booklist (book*)> <!ELEMENT type (#PCDATA)> <!ELEMENT title (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)> <!ELEMENT published_date (year, month)> <!ELEMENT year (#PCDATA)> <!ELEMENT month (#PCDATA)> <!ELEMENT note (#PCDATA)> |
次のコードは、書籍リストの情報を含むXML文書booklist.xmlです。ただし、先に示したDTDに従っておらず、
| <?xml version="1.0" encoding="shift_jis"?> <author>Donald Ervin Knuth</author> <price>134.95</price> <published_date> <year>1998</year> <month>10</month> </published_date> </book> <book> <type>novel</type> <title>Hannibal</title> <author>Thomas Harris</author> <published_date> <year>1999</year> <month>07</month> </published_date> <note>Best Seller!</note> </book> <book> <type>business</type> <title>Business @ the Speed of Thought</title> <author>Bill Gates</author> <subauthor>Collins Hemingway</subauthor> <price>13.56</price> <published_date> <year>2000</year> <month>05</month> </published_date> </book> </booklist> |
このような場合、このXML文書はXMLの構文には従っており、整形式のXML文書ではありますが、検証済みのXML文書ではありません。したがって、このXML文書を処理する際、DTD検証を行わない場合はエラーになりません。
検証を行うXMLファイルの読み込み
iPEXの提供するXML文書読み込み機能を持つクラスXMLReaderは、デフォルトでは検証を行いません。したがって、次のようなコードを記述した場合、booklist.xmlの読み込み処理は正常終了し、XMLReader::read()はtrueを返します。
| Stream::InputStreamByFile ifs(filename); XMLReader reader(&ifs); Document* pDoc = IPEXDocument::createDocumentObject(); Bool result = reader.read(pDoc); |
読み込み時にDTDによる検証を行うためには、次のようにXMLReaderを作成するときのフラグにReader::VALIDATEを指定します。
| Stream::InputStreamByFile is("booklist1.xml"); XMLReader reader(&is, Reader::VALIDATE); |
検証エラー内容の取得
検証時のエラー情報を取得するには、クラスDOMErrorHandlerの派生クラスを作成し、そのクラスのインスタンスをXMLReaderに渡します。このサンプルでは、エラー情報を取得するために、DOMErrorHandlerの派生クラスMyErrorHandlerを作成し、クラスXMLReaderのインスタンスに渡します。
| Stream::InputStreamByFile is("booklist1.xml"); MyErrorHandler handler; XMLReader reader(&is, Reader::VALIDATE, &handler); |
次はクラスMyErrorHandlerの宣言(MyErrorHandler.h)の一部です。
| #include < ipexdom.h > class MyErrorHandler : public iPEX::DOM::DOMErrorHandler { public: // Fatal Errorが起きたときの処理 virtual void fatalError(Code code, const iPEX::DOM::Node* pNode, unsigned int nLine, const iPEX::DOM::DOMString& strHint); // Errorが起きたときの処理 // Warningが起きたときの処理 |
クラスDOMErrorHandlerは仮想メンバ関数を3つ持っています。各仮想メンバ関数の役割は次の表のようになっています。
| 関数名 | 動作 |
| virtual void fatalError() | Fatal Errorが起きたときの処理 |
| virtual void error() | Errorが起きたときの処理 |
| virtual void warning() | Warningが起きたときの処理 |
XML文書読み込み処理の過程で検証エラーが発生した場合、上記の仮想メンバ関数error()が呼び出されます。
次にMyErrorHandler::error()の実装の一部(MyErrorHandler.cpp)を示します。このようなコードを記述することにより、発生したエラーに応じた処理を行うことができます。
| void MyErrorHandler::error(Code code, const iPEX::DOM::Node* pNode, unsigned int nLine, const iPEX::DOM::DOMString& strHint) { switch (code) { case E_UNDEFINED_ELEMENT: os << "Line:" << nLine << " 宣言されていないエレメントです。" << std::endl; break; ・・・その他のcaseを処理・・・ default: |
検証はXMLReader::read()にてXML文書の読み込みが行われるタイミングで実行されます。
実行結果
サンプルプログラムはコマンドプロンプトにて次のコマンドを用いることにより、XMLファイルbooklist.xmlのDTDによる検証を実行することができます。
| C:\> validator booklist.xml /v |
次に、このサンプルプログラムの実行結果を示します。
| Line:14 エレメントのコンテンツが不正です。 Line:14 エレメントのコンテンツが不正です。 Line:14 エレメントのコンテンツが不正です。 Line:24 エレメントのコンテンツが不正です。 Line:24 エレメントのコンテンツが不正です。 Line:24 エレメントのコンテンツが不正です。 Line:24 エレメントのコンテンツが不正です。 Line:28 宣言されていないエレメントです。 Could not read xml: booklist.xml |
© 2001 Infoteria Corporation












