Shammer's Philosophy

My private adversaria

DTD定義されたXMLを解析する

先日のXML文書に合わせてDTDを作成し、そのDTD定義を追加したXMLを解析するサンプルを書いてみる。
まず、DTD定義は次のようになる。

<!ELEMENT sample (elementA|elementB)*>
<!ELEMENT elementA (name) >
<!ELEMENT name (#PCDATA) >
<!ELEMENT elementB (someTag)>
<!ATTLIST elementB someAttr CDATA #REQUIRED>
<!ELEMENT someTag EMPTY>
<!ATTLIST someTag value CDATA #REQUIRED>

それぞれの行は、次のような意味を持つ。

  • sample要素は、elementA要素、またはelementB要素を複数個持つ
  • elementA要素は、子要素としてname要素を持つ
  • name要素は子要素を持たない文字列
  • elementB要素は、子要素としてsomeTag要素を持つ
  • elementB要素は、属性としてsomeAttr属性を持ち、このsomeAttr属性は必須(#REQUIRED)
  • someTag要素は子要素を持たない空要素である
  • someTag要素は、属性としてvalue属性が必須

そして、XMLは次のようになる。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sample SYSTEM "sample.dtd">
<sample>
  <elementA>
    <name>ElementA_Name</name>
  </elementA>
  <elementB someAttr="B">
    <someTag value="someValue"/>
  </elementB>
</sample>

Javaの実装は次のようになる。なお、JDKは1.4.x系のものを想定しており、Xercesは1.4.3を利用している。

import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ErrorHandler;
import org.apache.xerces.parsers.DOMParser;
import java.io.IOException;

public class MySimpleParseWithValidation {
    public static void main(String[]args){
	try {
	    DOMParser parser = new DOMParser();
	    parser.setFeature("http://xml.org/sax/features/validation", true);
	    parser.parse(args[0]);
	    Document doc = parser.getDocument();
	    System.out.println(args[0] + " is a valid xml.");
	}
	catch( SAXException e ){
	    System.err.println("Parser error found: " + e.getMessage());
	    System.exit(1);
	}
	catch( IOException e ){
	    System.err.println("IO error found: " + e.getMessage());
	    System.exit(1);
	}
    }
}

DTDの検証を指示しているのは、

    parser.setFeature("http://xml.org/sax/features/validation", true);

という行。このsetFeatureメソッドは2つの引数が必要。
一つ目の文字列引数は、パーサに対してどのオプションを設定するか知らせるもの。
"http://xml.org/sax/features/validation"の場合は、妥当性チェックの実施可否を指定する。
第二引数がtrueなので、この例だと妥当性チェックが実施される。
falseの場合は、妥当性チェックは実施されず、整形式かどうかだけのチェックが行われる。
また、第一引数で定義できる文字列値は決まっており、存在しないものを指定した場合は実行時にSAXExceptionが投げられる。