基本方針 †
- 基本的にSAX?でやったこととと同じやり方です。
- javax.xml.parsers.SAXParser#parse() でXMLをParseする。
- Parse中に発生するイベントをイベントハンドラで拾う。
- 今回はSAX?でやったのとは違い、タグや属性を拾うのではなくエラー発生イベントを拾います。
- SaxParserFactory? に以下の設定をしてから SAXParser を作成すると、SAXParser はエラーイベントを発生させるようになります。
spfactory.setFeature("http://xml.org/sax/features/namespaces", true);
spfactory.setFeature("http://xml.org/sax/features/validation", true);
spfactory.setFeature("http://apache.org/xml/features/validation/schema", true);
それぞれ、「namespaceを考慮する」「妥当性の検証をする」「XMLSchemaによる検証をする」ということを示します。
- 検証エラーが発生したら Stack につみながら最後までXMLを読み、読み終わってから Stack を見てどのようなエラーが発生したのかを調べます。
- XMLの検証はJDK自体の機能ではなくApacheのXercesというライブラリによって行われます
ライブラリの取得 †
- JDK1.5にはXercesがデフォルトで含まれるので特にライブラリの取得は必要ない
- JDK1.4にはCrimsonがデフォルトで含まれるのが、このライブラリはXMLSchemaを扱えないのでXercesをインストールする必要がある
- JDKの設定を変えて良い場合
- http://xml.apache.org/
から
Xerces-J-bin.2.7.1.zip
をダウンロードする。
- 展開してで来た
xercesInmpl.jar
xml-apis.jar
resolver.jar
を ${JAVA_HOME}/jre/lib/endorsed にコピーする。
このディレクトリにあるライブラリは、JDKに含まれるライブラリよりも優先して使われる
- JDKの設定を変えてはいけない場合
- 以下のライブラリをクラスパスに加える
xercesInmpl.jar
xml-apis.jar
resolver.jar
- ソースコード上で、
SAXParserFactory? の代わりに明示的に org.apache.xerces.jaxp.SAXParserFactoryImpl? を使います
- JDK1.3の場合には以下の手順でXMLパーサーをインストールする
xercesInmpl.jar
xml-apis.jar
resolver.jar
をクラスパスに加える
検証するXML †
- employee.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="employee">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="id" type="xs:integer" minOccurs="1" maxOccurs="1"/>
<xs:element name="telephone">
<xs:complexType>
<xs:sequence>
<xs:element name="cell" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="office" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
- correctEmployee.xml
<?xml version="1.0" encoding="UTF-8"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./employee.xsd">
<name>山田太郎</name>
<id>001</id>
<telephone>
<cell>001-1234-5678</cell>
<office>09-8765-4321</office>
</telephone>
</employee>
- badEmployee.xml
<?xml version="1.0" encoding="UTF-8"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./employee.xsd">
<name>山田花子</name>
<id>一番</id>
<telephone>
<office>09-8765-4321</office>
</telephone>
</employee>
検証プログラム †
package com.foo;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public final class XMLSchemaCheckExample {
/**
* 検証エラーの格納場所
*/
Stack parseErrorStack = new Stack();
public static void main(String[] args) {
XMLSchemaCheckExample example = new XMLSchemaCheckExample();
example.check();
}
public void check() {
try {
SAXParserFactory spfactory = SAXParserFactory.newInstance();
// 明示的にXercesを使う場合
// SAXParserFactory spfactory
// =org.apache.xerces.jaxp.SAXParserFactoryImpl.newInstance();
spfactory.setFeature("http://xml.org/sax/features/namespaces", true);
spfactory.setFeature("http://xml.org/sax/features/validation", true);
spfactory.setFeature("http://apache.org/xml/features/validation/schema", true);
SAXParser parser = spfactory.newSAXParser();
parser.parse(new File("employee.xml"), new ParseErrorHandler());
for (Iterator it = parseErrorStack.iterator(); it.hasNext();) {
System.out.println(it.next());
}
} catch (SAXException e) {
// SAXParserの初期化エラー時
// parser.parse()時のエラーでないことに注意
e.printStackTrace();
} catch (ParserConfigurationException e) {
// SAXParserの初期化エラー時
e.printStackTrace();
} catch (IOException e) {
// ファイルが読み込み無かったとき
e.printStackTrace();
}
}
/**
* XML読み込み中のエラーイベントを取得してスタックに積みます
*/
private class ParseErrorHandler
extends org.xml.sax.helpers.DefaultHandler {
public void error(SAXParseException ex) throws SAXException {
StringBuffer sbuf = new StringBuffer();
sbuf.append("ERROR");
sbuf.append("[");
sbuf.append(ex.getLineNumber() + "行");
sbuf.append(ex.getColumnNumber() + "桁");
sbuf.append("]");
sbuf.append(ex.getLocalizedMessage());
parseErrorStack.add(sbuf.toString());
}
public void fatalError(SAXParseException ex) throws SAXException {
StringBuffer sbuf = new StringBuffer();
sbuf.append("FATAL ERROR");
sbuf.append("[");
sbuf.append(ex.getLineNumber() + "行");
sbuf.append(ex.getColumnNumber() + "桁");
sbuf.append("]");
sbuf.append(ex.getMessage());
parseErrorStack.add(sbuf.toString());
}
public void warning(SAXParseException ex) throws SAXException {
StringBuffer sbuf = new StringBuffer();
sbuf.append("WARNING");
sbuf.append("[");
sbuf.append(ex.getLineNumber() + "行");
sbuf.append(ex.getColumnNumber() + "桁");
sbuf.append("]");
sbuf.append(ex.getMessage());
parseErrorStack.add(sbuf.toString());
}
}
}
実行結果 †
- correctEmployee.xmlの検証結果
- badEmployee.xmlの検証結果。
ERROR[5行14桁]cvc-datatype-valid.1.2.1: '一番' is not a valid value for 'integer'.
ERROR[5行14桁]cvc-type.3.1.3: The value '一番' of element 'id' is not valid.
ERROR[7行12桁]cvc-complex-type.2.4.a: Invalid content was found starting with
element 'office'. One of '{"":cell}' is expected.
XMLの入力ソース †
- SAXParserの入力ソースとしては以下の3つがある
javax.xml.parsers.SAXParser#parse(File f, DefaultHandler dh)
javax.xml.parsers.SAXParser#parse(InputStream is, DefaultHandler dh)
javax.xml.parsers.SAXParser#parse(String uri, DefaultHandler dh)
- Stringの検証をするには一度InputStream?にしてやればいい
InputStream is = new ByteArrayInputStream( str.getBytes("UTF-8") );
parser.parse(is,hander);
- RDBのCLOB領域にあるXMLの検証
Statement stmt = connection.createStatement();
String sql="SELECT EMP_XML FROM EMPLOYEE_TBL WHERE ID='001'";
ResultSet res=statement.executeQuery(sql);
res.first();
parser.parse(res.getCharacterStream(1),handler);
参考文献 †
- Sun, 2005, Java 2 Platform Standard Edition 5.0 の互換性, http://java.sun.com/j2se/1.5.0/ja/compatibility.html
- Kuroのページ, XML Schemaページ, http://www.ki.rim.or.jp/~kuro/XML/XMLSchema/
- The Apache XML, http://xml.apache.org/
- 山田祥寛(Wings), 2005, XMLSchemaを使ったXMLファイルの妥当性検証を行う, http://www.atmarkit.co.jp/fjava/javatips/129java024.html
Java