txqz memo

汎用Atomオブジェクトを自作するのは骨が折れすぎ

汎用Atomオブジェクトを作るのは骨が折れすぎ。

第1に拡張要素の問題がある。http://purl.com/ns/atom# 名前空間に属さない要素についてどんな処理をすれば良い? 木構造写像でも使えってか?

第2にtype属性値がxhtmlであるcontent要素の問題。テキストで持つにしてもブロック要素の後には改行を入れたいですなぁ。些細過ぎるか。

第3にSAXでの処理の限界がある。たとえば、ある要素については、feed要素からentry要素へ値の継承が行われる。feed要素がauthor要素を持っていてentry要素はauthor要素を持っていない場合、feed要素下のauthor要素の値が各entry要素に継承されるとみなされる 。さらに要素の出現順序には規制がないので、SAXのような順序処理では対応しきれない場合もある。たとえば以下のような場合。

<feed xmlns="http://purl.org/ns/atom#">
  <title>いやなFeed</title>
  <id>iyana-id</id>
  <updated>2007-04-21 20:57:21</updated>
  <entry>
    <title>いやなEntry</title>
    <id>iyana-entry-1</id>
    <link rel="alternate" href="http://example.com/iyana/uri" />
    <update>2007-04-21 20:57:21/update>
  </entry>
  <author><name>いやなName</name></author>
</feed>

entry要素のあとにauthor要素が出てきた場合、このauthor要素の値を忠実にentry要素に継承させようと思ったら、それをSAXでゴリゴリ書くのは見通しがいかにも暗くて気が進まない。

ではDOMならいいのかというと、getElementsByTagName()メソッドは名前が同じならどこに出現する要素でも拾ってしまうという大問題がある。feed要素直下のtitle要素が必要なのに、getElementsByTagName("title");なんてやるとentry要素下のtitle要素にもマッチしてしまう (実際はtitle要素はAtom1.0名前空間下にあるので 、getElementsByTagNameNS()メソッドを使う) 。要素の出現順序に制限はないので、0番目のtitleがfeed直下のものだろうという仮定もできない。Atomの使用策定過程を追っていくと、head要素が定義されているものも見つかる。head要素があればDOM処理もいくらか楽になったかもしれないが、正式な仕様からhead要素は削除された。

ということで、残された道はXpathくらいか? ということになった。

Digesterを使うという話があったが、Digesterって、XPathでいうところの//link [@rel='alternate']/@href (rel属性値が"alternate"であるlink要素のhref属性値) みたいな指定はできるのだろうか。いや、処理中に条件分岐とかすれば良いんだけど、どうせやるならなるべくスマートにやりたい。

XMLBeansを使うという話もあったが、なんか、大掛かりすぎる気がしてしっくりこない。あとサイトにある日本語の調子がいかにも翻訳調で萎える。

結局Atomパーサの望ましい形とはどのようなものなのだろうか。

Atomの文法に準拠して、0個か1個または必ず1個出現するものはObjectまたはStringで、0個以上出現するものはListで保持し、外来要素についてはそのままDOMの形で持っていてくれるものがいいかなあ。Objectは実際には要素のコンストラクトや保持する属性を反映した具象オブジェクトとする。いや、もう全部Mapで良いかもしれない。いや、そもそも全部DOMで良いかもしれない。getEntries()とかgetTitle()とかのメソッドの内部でXPATH式を評価してあげれば良いだけの話だ。んー。