解答例 - 実習課題1 - 6.DTD(DocumentType)
(実習課題1)
XMLパーサには、DTDを解読した上でXML文書がDTDに沿った構造になっているか解析するvalidate機能が提供されています。ただし、アプリケーションで使用するXMLの構造があらかじめ決まっている場合、パーサがDTDを読み取る処理がオーバーヘッドになります。そこで、以下のコンソールプログラムを作成しなさい。
- 引数に与えられたXML文書が、以下のDTDで表される構造になっているか、判定するプログラム
- 与えられたXMLが以下の条件を満たすときのみ、DTDに沿ったXMLファイルかどうか、解析する。解析結果は標準出力に表示する。
- ルート要素 :person
- 公開識別子: -//Four Dimensional Data, Inc.//DTD DOM Example 1.0//EN
- システム識別子: http://www.techscore.com/tech/Java/DOM/DOMExample.dtd
- 上記以外のDTDが指定されている場合、エラーメッセージを標準エラーに出力し、プログラムを終了する。
- XMLパーサのvalidate機能を使用しない。
Java 1.4付属のパーサを使用する場合、デフォルトでXMLパーサのvalidate機能は使用できないようになっています。また、以下のようにして、validate機能を使用しないように設定することが可能です。DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false);
- 解析するXML文書にコメントやエンティティは含まれないものとしてよい。
- DTDは以下の通り。
<!-- person要素がルート要素となる --> <!ELEMENT person (name,age,license*)>
※"http://www.techscore.com/tech/Java/DOM/DOMExample.dtd"が参照できる環境でプログラムを実行する必要があります。
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT license (#PCDATA)>
解答例
package com.techscore.dom.chapter6.exercise1; import java.io.File; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * DtdValidator.java * * TECHSCORE Java XML DOM XSLT 6章 実習課題1 * * Copyright (c) 2004 Four-Dimensional Data, Inc. */ public class DtdValidator { private static final String[] ELEMENT_NAMES = {"name", "age", "license"}; public static void main(String[] args) throws Exception { if (args.length < 1) { System.out.println("引数にXML文書ファイルを指定してください"); return; } DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); Document document = factory.newDocumentBuilder() .parse(new File(args[0])); DocumentType dtd = document.getDoctype(); if(dtd == null){ System.err.println("DOCTYPE宣言がありません"); return; } // XMLファイルを解析するかどうか判定する Element person = document.getDocumentElement(); if ((!"person".equals(dtd.getName())) || (!"-//Four Dimensional Data, Inc.//DTD DOM Example 1.0//EN".equals(dtd.getPublicId())) || (!"http://www.techscore.com/tech/Java/DOM/DOMExample.dtd".equals(dtd.getSystemId()))) { System.err.println("DTDが規定されたものではありません"); return; } int idx = 0; NodeList nodeList = person.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { if (nodeList.item(i).getNodeType() == Node.ELEMENT_NODE) { if (!ELEMENT_NAMES[Math.min(idx++, 2)].equals(nodeList.item(i) .getNodeName())) { System.err.println("このXML文書は" + "『<!ELEMENT person (name,age,license*)>』" + "という指定に従っていません"); return; } else if (nodeList.item(i).hasChildNodes()) { NodeList childList = nodeList.item(i).getChildNodes(); for (int j = 0; j < childList.getLength(); j++) { if (childList.item(j).getNodeType() != Node.TEXT_NODE) { System.err.println("このXML文書は" + "『<!ELEMENT " + nodeList.item(i).getNodeName() + " #PCDATA』" + "という指定に従っていません"); return; } } } } else if (nodeList.item(i).getNodeType() == Node.TEXT_NODE) { if (!nodeList.item(i).getNodeValue().matches("\\s*")) { System.err.println("このXML文書には、不正な文字列が含まれています"); return; } } } System.out.println("このXML文書は規定のDTDに従っています"); } }