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