基本方針

  1. 基本的にSAX?でやったこととと同じやり方です。
    • javax.xml.parsers.SAXParser#parse() でXMLをParseする。
    • Parse中に発生するイベントをイベントハンドラで拾う。
  2. 今回はSAX?でやったのとは違い、タグや属性を拾うのではなくエラー発生イベントを拾います。
    1. 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による検証をする」ということを示します。
    2. 検証エラーが発生したら Stack につみながら最後までXMLを読み、読み終わってから Stack を見てどのようなエラーが発生したのかを調べます。
  3. XMLの検証はJDK自体の機能ではなくApacheのXercesというライブラリによって行われます

ライブラリの取得

  1. JDK1.5にはXercesがデフォルトで含まれるので特にライブラリの取得は必要ない
  2. JDK1.4にはCrimsonがデフォルトで含まれるのが、このライブラリはXMLSchemaを扱えないのでXercesをインストールする必要がある
    1. JDKの設定を変えて良い場合
      1. http://xml.apache.org/
        から
        Xerces-J-bin.2.7.1.zip
        をダウンロードする。
      2. 展開してで来た
        xercesInmpl.jar
        xml-apis.jar
        resolver.jar
        を ${JAVA_HOME}/jre/lib/endorsed にコピーする。
        このディレクトリにあるライブラリは、JDKに含まれるライブラリよりも優先して使われる
    2. JDKの設定を変えてはいけない場合
      1. 以下のライブラリをクラスパスに加える
        xercesInmpl.jar
        xml-apis.jar
        resolver.jar
      2. ソースコード上で、
        SAXParserFactory? の代わりに明示的に org.apache.xerces.jaxp.SAXParserFactoryImpl? を使います
  3. JDK1.3の場合には以下の手順でXMLパーサーをインストールする
    xercesInmpl.jar
    xml-apis.jar
    resolver.jar
    をクラスパスに加える

検証するXML

  1. 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>
  2. 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>
  3. 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());
    }
  }
}

実行結果

  1. correctEmployee.xmlの検証結果
  2. 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の入力ソース

  1. 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)
  2. Stringの検証をするには一度InputStream?にしてやればいい
    InputStream is = new ByteArrayInputStream( str.getBytes("UTF-8") );
    parser.parse(is,hander);
  3. 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);

参考文献

  1. Sun, 2005, Java 2 Platform Standard Edition 5.0 の互換性, http://java.sun.com/j2se/1.5.0/ja/compatibility.html
  2. Kuroのページ, XML Schemaページ, http://www.ki.rim.or.jp/~kuro/XML/XMLSchema/
  3. The Apache XML, http://xml.apache.org/
  4. 山田祥寛(Wings), 2005, XMLSchemaを使ったXMLファイルの妥当性検証を行う, http://www.atmarkit.co.jp/fjava/javatips/129java024.html

Java


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS   sitemap
Last-modified: 2006-02-18 (土) 13:43:44 (6868d)
Short-URL: http://at-sushi.com/pukiwiki/index.php?cmd=s&k=369b6483f1
ISBN10
ISBN13
9784061426061