JAXB で DTD 妥当性検査をしたり、エンコーディングを指定したり

以下、テストケースを書くのに若干悩んだのと、忘れそうなのでメモ。

Jaxb2Marshaller のプロパティを指定する

Spring の Jaxb2Marshaller に対して、エンコードなど指定できる。

javax.xml.bind.Marshaller のサポートされているプロパティを参照

プロパティ 意味
jaxb.encoding XML データを整列化するときに使用される出力エンコーディング
jaxb.formatted.output Marshaller が改行とインデントを使用して結果として得られる XML データを書式設定するかどうかを制御
jaxb.schemaLocation xsi:schemaLocation 属性をクライアントアプリケーションが指定することができます
jaxb.noNamespaceSchemaLocation 生成 XML データの xsi:noNamespaceSchemaLocation 属性をクライアントアプリケーションが指定することができます
jaxb.fragment 文書レベルのイベントが Marshaller によって生成されるかどうかを決定します

 

設定ファイルでは、以下の様に上記プロパティを設定できる。

<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list> .... </list>
    </property>
    <property name="marshallerProperties">
        <map>
            <entry>
                <key>
                    <util:constant static-field="javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT" />
               </key>
              <value type="java.lang.Boolean">true</value>
            </entry>
        </map>
    </property>
</bean>

動的にプロパティを変更する場合は、以下の様に setMarshallerProperties に設定できる。

/**
 * ObjectをXML出力する
 * @param marshaller Jaxb2Marshaller のインスタンス
 * @param obj XML化するオブジェクト
 * @param encoding XMLのエンコーディング
 * @isFragment XML宣言を出力しない場合 true
 * @isFormatted 書式整形する場合 true
 */ 
protected String objectToXml(Jaxb2Marshaller marshaller, Object obj, String encoding, boolean isFragment, boolean isFormatted){
    
    try {
        String fileEnc = "UTF-8";
        
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        StreamResult result = new StreamResult(os);
        
        if (isFragment || isFormatted || (encoding != null)) {
            Map<String, Object> properties = new HashMap<String, Object>();
            if (encoding != null) {
                fileEnc = encoding;
                properties.put("jaxb.encoding", encoding);
            }
            if (isFragment) {
                properties.put("jaxb.fragment", Boolean.TRUE);
            }
            if (isFormatted) {
                properties.put("jaxb.formatted.output", Boolean.TRUE);
            }
            marshaller.setMarshallerProperties(properties);
        }
        marshaller.marshal(obj, result);
        return os.toString(fileEnc);
        
    }catch (Exception e) {
        e.printStackTrace();
    }
}

DOCTYPEの出力

JAXBのアノテーションとかで、DOCTYPEの出力くらいできそうなものだが、どうやっていいかわからない。というかできなさそう。。。

ただ上記 Jaxb2Marshaller の jaxb.fragment プロパティは、JavaDoc にあるように、marshal(Object,OutputStream)や、marshal(Object,Writer) で呼び出した場合、XML 宣言を生成しない。

これを利用して、XML宣言と、DOCTYPE部分は自分で出力する。

Task は対象となるオブジェクト。dtd ファイルは、下記例では、c:\work\test\upload.dtd に実際にDTDファイルを置いておく。エンコーディングも指定している。

XML宣言と、DOCTYPEは自力で作成し、StringBuffer に突っ込んで、最終的なXMLを検査メソッドに渡す。

Task task = new Task();
String encode = "ISO-8859-1";
String dtd = "file:///C:/work/test/upload.dtd";
String type = Task.class.getSimpleName();
boolean isFragment = true;
String xmlFragment = objectToXml(imdsJaxb2Marshaller, task, encode, isFragment, true);

StringBuffer xml = new StringBuffer();
xml.append(String.format("<?xml version=\"1.0\" encoding=\"%s\">\n",encode));
xml.append(String.format("<!DOCTYPE %s SYSTEM \"%s\">\n",type, dtd));
xml.append(xmlFragment);

dtdValidation(xml.toString());

DTDの妥当性検査

ここで、いろんなパターンの妥当性検査例サンプルがあるので参考に、dtdValidateion() メソッドを記述。

protected void dtdValidation(String xml) {
    try {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setValidating(true);
        factory.setNamespaceAware(true);

        SAXParser parser = factory.newSAXParser();

        XMLReader reader = parser.getXMLReader();
        reader.setErrorHandler(new SimpleErrorHandler());
        reader.parse(new InputSource(new StringReader(xml)));
    
    }catch(Exception e) {
        e.printStackTrace();
    }
}   

private static class SimpleErrorHandler implements ErrorHandler {
    public void warning(SAXParseException e) throws SAXException {
        System.out.println(e.getMessage());
    }

    public void error(SAXParseException e) throws SAXException {
        System.out.println(e.getMessage());
    }

    public void fatalError(SAXParseException e) throws SAXException {
        System.out.println(e.getMessage());
    }
}

いじょう。

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です