HaskellでTwitterクライアント開発blog(仮)

今すぐに挫折するかもしれない程度のモチベーションによるTwitterクライアント開発記

タイムラインのJSONデータを解析してみる(Text.JSON)

API利用は前回できましたので、次はタイムラインの取得を。
とは言ったものの、CUIなので見栄えはしませんが……
自動更新もつけてません。

自分のアカウントのタイムラインを取得するには、home_timelineを使えばOK。
パラメータはいりませんが、いろいろとオプションで付けることができます。
何もパラメータを付けずにリクエストすると、最新20件のツイートを取得します。

このとき、データの形式は色々と選ぶことができるのですが、
今回はJSON形式を使ってみました。

HaskellにはJSON解析ライブラリがあります。
cabal install JSONでText.JSONモジュールを使います。

 decode :: JSON a => String -> Result a 

でJSONデータの文字列をパースしてくれます。

取得データの形式は次のようになってました。

・(home_timelineで取得できるデータ) = JSArray [(tweet)] (各tweetが最新のものから順に入っている)

・(tweet) = JSObject JSValue (各ツイートのデータ)

・ツイートのデータにはさらに"user"フィールドというJSObject型の値が存在し、ここにツイートしたアカウントの詳細なデータが入っている

ツイートのデータはかなり多いのでここに書くのは省略……
JSObject型は、fromJSObject関数で連想リストの形に変換できるので、
変換して目的のデータをデータ名で指定して取得する関数、及び取り出したJSValue型から目的の型にあったデータを取得してくる関数を作ることで、
各フィールドの値にアクセスするようにしました。

-- ツイート
data Tweet = Tweet {
      name :: String, -- ユーザ名
      screen_name :: String, -- ユーザID
      retweeted :: Bool, -- リツイートされたか
      created_at :: String, -- ツイートされた時刻
      profile_image_url :: String, -- プロフィール画像
      text :: String -- ツイート内容
}

-- オブジェクト名指定で対応するJSONオブジェクトの値を取得
findJSObject :: Monad m => JSObject a -> String -> m a
findJSObject jsobject objectName =
case dropWhile ( (/= objectName) . fst) (fromJSObject jsobject) of
[] -> fail $ "findJSObject: Not_found(\"" ++ objectName ++ "\")"
object:_ -> return . snd $ object

ofJSBool :: Monad m => JSValue -> m Bool
ofJSBool (JSBool b) = return b
ofJSBool _ = fail "ofJSBool: Not JSBool"

ofJSString :: Monad m => JSValue -> m String
ofJSString (JSString str) = return $ fromJSString str
ofJSString _ = fail "ofJSBool: Not JSString"

ofJSObject :: Monad m => JSValue -> m (JSObject JSValue)
ofJSObject (JSObject jsobject) = return jsobject
ofJSObject _ = fail "ofJSBool: Not JSObject"

-- ツイートを取得
getTweet :: Monad m => JSObject JSValue -> m Tweet
getTweet jsobject = do
user <- ofJSObject =<< findJSObject jsobject "user"
name <- ofJSString =<< findJSObject user "name"
screen_name <- ofJSString =<< findJSObject user "screen_name"
retweeted <- ofJSBool =<< findJSObject jsobject "retweeted"
created_at <- ofJSString =<< findJSObject jsobject "created_at"
profile_image_url <- ofJSString =<< findJSObject user "profile_image_url"
text <- ofJSString =<< findJSObject jsobject "text"
return $ Tweet name screen_name retweeted created_at profile_image_url text

それなりに使いやすいインタフェースに出来たかなと思います。
各関数において、不正なデータ型が来たらエラーにするようにしてあります。(ofJSBool, ofJSString, ofJSObject)

で、コードですが、ようやくgithubに上げました。

リポジトリ
https://github.com/xenophobia/hshstter