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