ちょっとした必要に迫られて XML を Java クラスにバインディングしてくれるツールについて調べた事の覚え書き。
JAXB
何かのライブラリとかツール群の中に同梱されているのは何度か見かけたけど、
自分で使ってみたのは初めてだったので手順をメモっとこう。
  1. 扱いたい XML の構造が分かっている場合、まず XML Schema を作成する。
  2. XML Schema から Java のクラスを生成する。
  3. 扱いたい XML をアンマーシャルして Java クラスにバインディング。
1. は勿論手で書いてもいいけど、ちょっと複雑になってくるとかなりしんどいのでツールに任せた。
trangrelaxer が使える。
java -jar trang.jar <元のxml> <生成するxsd>
relaxer -xsd <元のxml>
2. は Java 標準の xjc を使用する。
xjc <1.で生成したxsd>
同ディレクトリにワラワラっと Java クラスが生成される。
3. はこの辺のサンプルを参考に。

一応やりたいことはできたけど、xsd の作成に一手間かかる上に
生成されるクラスが無駄に多め(これは xsd の書き方が悪いのかもしれないけど)だったり
XML の構造が変わったらまた1. ~3. をやり直さないといけなかったりして、
もうちょっとお手軽にできないものかと他の方法を探してみた。
Commons Digester
JAXB ほど事前にやる事は多くないけど、 XML → Java のみが可能で、その逆はできない。
XML の構造をパターンとして記述し、そのパターン出現時に行う処理を Digester に定義する。
例えばルート要素が root の場合に Root クラスにバインディングしたい場合、
digester.addObjectCreate("root", Root.class);
こんな感じで Root クラスを作るようにしている。 なまえ の 「なまえ」を Root クラスの name 変数にセットする場合、
digester.addBeanPropertySetter("root/name");
とする。 XML の要素名と Java 変数名が異なる場合は
digester.addBeanPropertySetter("root/name", "namae");
とプロパティ名を指定する。

属性を扱う場合、
digester.addSetProperties("root/name");
とすれば、要素の全属性を Root クラスの同名変数に設定してくれる。
特定の属性のみ取得したい場合、
digester.addSetProperties("root/name", "id", "id");
のように、第二引数で属性名を、第三引数で Java 変数名を指定する。

名前空間の扱いはちょっと注意が必要。
デフォルトではプレフィックスを指定できる。
なまえ では、
digester.addObjectCreate("a:root", Root.class);
digester.addBeanPropertySetter("a:root/b:name", "name");
でちゃんと動作してしまう。
しかしこれではイケてないので、ちゃんと名前空間 URI との一致で解釈させるようにしたい。
digester.setNamespaceAware(true);
digester.setRuleNamespaceURI("http://xxx");
digester.addObjectCreate("root", Root.class);
digester.setRuleNamespaceURI("http://yyy");
digester.addBeanPropertySetter("root/name", "name");
このように URI を設定し直しつつ定義していかないといけない模様…。
後述するけど名前空間の扱いはいまいち不安定さを感じる。

まとめとして、mixi アプリの Person & Friends API レスポンスサンプル(application/atom+xml 形式)
Java クラスにバインディングする Digester 定義を書いてみた。
色々調べてみたけど、属性の名前空間対応はできていないのかも?
やり方を知らないだけかもしれないけど、どうも以下の id 属性は、どのような定義をしても
「最後に定義されている要素」(c:id)の値を取ってきているようだ。
全ての id を正確に URI とマッチさせつつ値を取得する方法を定義できなかった…。
<a:root xmlns:a="http://xxx" xmlns:b="http://yyy" xmlns:c="http://zzz">
<b:name a:id="a" b:id="b" c:id="c">なまえ</b:name>
</a:root>

Copyright© 2011-2021 Shunsuke Otani All Right Reserved .