なんかAtomPPをとあるサービスで実装しようとして、Atom1.0とJavaのオブジェクトをうまいこと変えてくれるようなのを探している。最初はDOMやSAXで行こうと思ったけれども、これはいかにも面倒だ。そもそも、DOMで getElementsByTagName("title");
とかすると、 /feed/title も /feed/entry/title も含まれてしまうのでよくない。 getElementsByTagName()
で得られたNodeListの0番目が /feed/title で残りが /feed/entry/title だと見なすもの危険だ。かといってSAXだと、オブザーバとか用意したり大変だし、要素の出現順序に制限がないのに一部の要素はfeedからentryへ値が継承されるというのを実装するのが厄介だ。まぁ、アレだったらXPathを使えばいいか。いや、そもそもAtom1.0はちゃんとRFCになっているわけだし、そんな公的なもののパーサをいちいち作らなければならないはずがない。
ということで今回はRomeを試してみた。JDOM1.0が必要なのであらかじめ用意しておく。試したもなにも、チュートリアル通りやっただけだ。
で、こんなAtom文書を読ませてみた。
<?xml version='1.0' encoding='UTF-8' ?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:txqz="http://txqz.net/" xmlns:xh="http://www.w3.org/1999/xhtml">
<title>てきとうなfeed</title>
<author><name>ようざか</name></author>
<id>tag:txqz.net,2007-04-24:nanika</id>
<updated>2007-04-24T21:16:32+09:00</updated>
<entry>
<title>朝起きて夜寝た</title>
<category term="life" label="生活" />
<content type="xhtml">
<xh:div>
<xh:p>こんにちは!こんにちは!</xh:p>
</xh:div>
</content>
<id>tag:oshira.se,2000:212</id>
<link rel="alternate" href="http://txqz.example.com/blog/212" />
<summary>朝のあいさつです><</summary>
<updated>2000-01-02T03:04:05+06:00</updated>
<txqz:exp>なんかentryの拡張要素</txqz:exp>
</entry>
<txqz:exp>なんかfeedの拡張要素1</txqz:exp>
<txqz:exp>なんかfeedの拡張要素2</txqz:exp>
</feed></code></pre>
<p>Java的にはこんな感じ:</p>
<pre><code class="java">SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new File("test.xml"));</code></pre>
<p>とりあえず各entryについて、title,id,updated,contentの各要素の値と、rel属性が"alternate"であるlink要素のhref属性の値を保管するようなクラスに代入していきたい。それが終わったら独自拡張要素txqz:exp (entry要素内に0回か1回出現するものとする) もクラスに代入してみよう。</p>
<p>保管クラスは以下のような感じ:</p>
<pre><code class="java">class Entry{
private String title;
private String id;
private String link;
private String date;
private String content;
private String exp;
// 以下setterとgetter
}
ROME側で:
List entries = feed.getEntries();
List<Entry> entryList = new ArrayList<Entry>();
for(Object o : entries){
SyndEntry entry = (SyndEntry)o;
Entry e = new Entry();
e.setTitle(entry.getTitle());
e.setId(entry.getUri());
e.setLink(entry.getLink());
e.setDate(entry.getUpdatedDate());
SyndContent content = (SyndContent)entry.getContents().get(0);
e.setContent(content.getValue());
entryList.add(e);
}
それぞれgetして表示してみると:
朝起きて夜寝た
tag:txqz.example.com,2000:212
http://txqz.example.com/blog/212
Sun Jan 02 06:04:05 JST 2000
<xh:div xmlns:xh="http://www.w3.org/1999/xhtml"><xh:p>こんにちは!こんにちは!</xh:p></xh:div>
link[@rel='alternate']/@href
は getLink()
で取得できるけれども、rel属性がほかの値になっているlink要素のhref属性値はどうやって取得するのだろう。あと、 SyndEntry#getContents()
は List
を返すメソッドで、単純に SyndContent
を返すようなメソッドは用意されていないみたい。RFC4287 にはatom:entry elements MUST NOT contain more than one atom:content element.
とあるので getContents()
メソッドってどうよ? という感じだが、ROMEはRSSやAtom0.3など多くのフォーマットに対応しているのがウリなので、そこら辺は仕方ない。あと時刻の値が Date#toString()
な感じになっているのが興味深い。MySQLに入れるには SimpleDateFormat
かなんかを使ってパースしなおさないといけなくなるぞ。
Dateな感じも何も、最初からDateオブジェクトが入っているだけだった。MySQLが受け取ってくれるような文字列に変えたければ、フツーに
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format();
とかやったらいい。
それはそれとして、独自拡張要素txqz:expの取得をしてみたい。 SyndEntry#getForeignMarkup()
を使う。さっきのforループで entryList.add(e);
する前に:
ArrayList list = (ArrayList) entry.getForeignMarkup();
Element exp = (Element) list.get(0);
e.setExp(exp.getValue());
SyndEntry#getForeignMarkup()
が返すObjectの正体はArrayList
で、その中にはjdomの Element
が入っている。なので、「何番目の独自拡張要素がほしい!」というのはできるが、「何々という名前の独自拡張要素がほしい!」と思ってもループをまわして Element#getName()
して条件分岐する必要が出てきてしまう。うーん。
なんかもっとこう、Atom1.0だったらこのパーサに任せておけば間違いない! みたいなものはないものか。引き続き探索中。