LodgonDemo の件

id:higepon さんが継続について色々ほぢくり返しているのに目がイッてしまいつつ、pending になったママの GWTRSS Reader なサンプルの不具合を検証。
とりあえずサンプルで取得しようとしている RSS はこんなかんじ。

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet ... (snip) ... ?>
<?xml-stylesheet ... (snip) ... ?>
<rss ... (snip) ... >

<channel>
 <title>i-wisdom</title>
 <link>http://i-wisdom.typepad.com/iwisdom/</link>

 <description>i-merge.net's Brandbreeding Blog</description>
 <language>en</language>
 <lastBuildDate>Wed, 20 Dec 2006 10:34:53 -0600</lastBuildDate>
 <generator>TypePad http://www.typepad.com/</generator>
 <image>
  <link>http://i-wisdom.typepad.com</link>
  <url>http://www.feedburner.com/fb/images/pub/fb_pwrd.gif</url>
  <title>Recent op de I-wisdom blog</title>
 </image>
 <atom10:link ... />
 <feedburner:browserFriendly> ....  </feedburner:browserFriendly>

 <item>
  <title>Top 10 usability bloopers</title>
  <link> ... </link>
  <category>WTF</category>
  <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">
   Dominique Poncin
  </dc:creator>
  <pubDate>Wed, 20 Dec 2006 10:34:53 -0600</pubDate>
  <guid isPermaLink="false">tag:typepad.com,2003:post-14770725</guid>

  <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/">
   <![CDATA[ ... (snip) ... ]]>
  </content:encoded>

  <description> ... (snip) ... </description>
 </item>

 <item>

 (以下略)

</rss>

構造としてはこうなるんでしょうか。
# rss タグで囲まれた部分のみ

  • channel
    • title
    • link
    • description
    • langage
    • lastBuildDate
    • generator
    • image
      • link
      • url
      • title
    • atom10
    • feedburner
    • item
      • title
      • link
      • category
      • dc:creator
      • pubDate
      • guid
      • content
      • description
    • item

(つづく)

処理しようとしてるのはコード的に言うと item で囲まれた一団を、と読めるんでそれを前提に話を進めてみます。(これがダウトだったら爆死だな

で、ちょっと長いんですが、RssFeedParser.java の一部を以下に。

  public void startElement (String uri, String localName, String qName, Attributes attributes) {
    if (! inContent) {
      this.text = new StringBuffer();
    }
    else { // this can probably be done MUCH better
      this.text.append("<").append(qName);
      int l = attributes.getLength();
      for (int i = 0; i < l; i++) {
        this.text.append(" ").append(attributes.getQName(i)).append("=\"").append(attributes.getValue(i)).append("\""); 
      }
      this.text.append (">");
    }
    if (("content".equals (qName)) || ("description".equals (qName)) ) {
      inContent = true;
    }
    if (("item".equals (qName)) || ("entry".equals (qName)) ) {
      this.target = new Entry();
      this.result.add (target);
    }
  }

  public void characters (char[] ch, int start, int length) throws SAXException {
    this.text.append (ch, start, length);
  }

  public void endElement (String uri, String localName, String qName) {
    if (inContent) {
      this.text.append("</").append(qName).append(">");
    }
    if (("item".equals (qName)) || ("entry".equals (qName)) ) {
      this.target = null;
    }
    if (this.target != null) {
      if ("title".equals (qName)) {
        this.target.setTitle (this.text.toString());
      }
      if ("id".equals (qName)) {
        this.target.setExternalId (this.text.toString());
      }
      if ("link".equals (qName)) {
        this.target.setExternalId(this.text.toString());
      }
      if (("description".equals (qName))  || ("content".equals (qName))){
        this.target.setSummary (this.text.toString());
        this.target.setContent (this.text.toString());
// System.out.println ("description = "+this.text);
this.inContent = false;
      }
     if (("media:category".equals (qName)) || ("dc:subject".equals(qName))) {
        this.target.setKeywords(this.text.toString());
System.out.println ("tags = "+this.text);
      }
      if (("pubDate".equals (qName))|| ("created".equals(qName))) {
        try {
          Date date = sdf.parse(text.toString());
          this.target.setCreationDate(date.getTime());
          SimpleDateFormat sdf2 = new SimpleDateFormat ("MMM d");
          this.target.setFormattedDate(sdf2.format (date));
          System.out.println ("fmd server = "+this.target.getFormattedDate());
        } catch (Exception e) {
e.printStackTrace();
          this.target.setCreationDate(System.currentTimeMillis());
        }
      }
    }

なんかほとんど引用しちゃってるし。(駄目

で、上記の endElement メソドの SimpleDateFormat#parse んトコで例外が発生している。メセジは以下。

java.text.ParseException: Unparseable date: "imerge.net's Brandbreeding Blog

上記に引用した XML 文書の先頭部分の description なデータですな。上で述べた通り、item タグで囲んであるデータが処理対象なのであれば、このデータが処理対象になっている時点でダウトな気がしますな。各メソドの処理を以下に箇条書きにしてみます。

  • startElement メソド
    • inContent が false なら this.text に StringBuffer なオブジェクトを new して参照を代入
    • inContent が true なら attributes を this.text に追加
    • qName (タグ) が content か description なら inContent を真に
    • qName (タグ) が item 又は entry なら this.target に Entry なオブジェクトを new して参照を代入しつつ、this.result (List オブジェクト) に this.target を追加
      • item (又は entry) の中に content か description が含まれるのが前提だったら上記の XML と整合してないな。例外発生の原因の一つと考える事ができる
  • character メソド
    • this.text にテキストデータを append
  • endElement メソド
    • inContent が真なら終了タグを this.text に append
    • qName (タグ) が item 又は entry なら this.target に null を設定
      • List#add ってオブジェクトがコピられる??って思ったら this.result で参照してるから行方不明にはならないのか。どうもアドレスで考える微妙なクセがナニ
    • 以下は this.target が null で (item 又は entry が閉じて) ない場合の処理 (てコトは item 又は entry タグ内にあるもので処理対象となるのは以下のタグ、となるはず
      • qName (タグ) が title の場合、this.target.setTitle メソド呼び出し
      • qName (タグ) が id の場合、this.target.setExternalID 呼び出し
      • qName (タグ) が link の場合、this.target.setExternalID 呼び出し
      • qName (タグ) が description 又は content の 場合、this.target.setSummary と this.target.setContent した後に inContent を false にしている。とゆー事は、inContent が true なのは item タグん中の description 又は content タグの処理中のみ、となるな
      • qName (タグ) が media:category 又は dc:subject の場合、this.target.setKeywords 呼び出し
      • qName (タグ) が pubDate 又は created の場合、日付変換後に this.target.setFormattedDate 呼び出し

てコトで startElement において、inContent を true にする条件分岐に this.target が null でない、という条件式を and 条件にて追加したら例外は発生しなくなったのですが、RssFeedParser#getPostings がオワりました、というコンソールメセジは出つつも動作が微妙だし。(困

つづき

実行するとダイアログが表示。メセジは以下。

Failed to load module 'com.lodgon.ajax.demo1.LodgonDemo'. Please see the log in the development shell for details.

Development Shell を見ると

  • Unable to load module entry point class com.lodgon.ajax.demo1.client.LodgonDemo
  • Failure to load module 'com.lodgon.ajax.demo1.LodgonDemo'

ってなんか変だなぁ。

追記

だめだ。全然整理できてねぇ。コマギレで作業しちゃ (以下略
GWT なエントリ見てるとダメダメ感満載ですな。