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());
}
}
いじょう。
