Clojure で GUI アプリを書いてみる ( HTTP, JSON 編)
昨日の続きです。
天気予報をアイコンで教えてくれるアプリを作りたいので、どこかから天気予報のデータを持って来なければいけません。
選択肢は色々あったのですが、 Clojure では XML のノード選択が意外と面倒くさかったので、今回は Livedoor Weather Web Service を使う事にしました。
使う API が決まったので、方針ももう決まったものです。
早速やってみましょう。
使うもの
- Leiningen 2.1.3
- Java 1.6.0_45
- clojure/data.json 0.2.2
- clj-http 0.7.2
まずは Leiningen で新しいプロジェクトを作ります。
今回のプロジェクト名は httptest にしておきましょう。
$ lein new httptest $ cd httptest
project.clj を以下のように編集。
(defproject httptest "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} ;; 今日は data.json と clj-http を依存ライブラリに追加 :dependencies [[org.clojure/clojure "1.5.1"] [org.clojure/data.json "0.2.2"] [clj-http "0.7.2"]] ;; 例によって、 lein run で走らせられるように main を記述 :main httptest.core)
ここで依存関係を解決しておきます。
$ lein deps
src/httptest/core.clj を以下のように編集。
(ns httptest.core (:require [clj-http.client :as client] [clojure.data.json :as json])) ;; とりあえず API の URL を def しておく。これは東京の天気予報 (def tenki-api-addr "http://weather.livedoor.com/forecast/webservice/json/v1?city=130010") ;; ロードして JSON をパース (defn get-tenki [] (let [tenki-data (client/get tenki-api-addr)] (json/read-str (:body tenki-data) :key-fn keyword))) ;; これを使えば天気予報の詳細文が出てくる(今回未使用) (defn tenki-dscr [json-tenki] (:description json-tenki)) ;; 今日の天気部分だけ取り出す (defn tenki-today [json-tenki] (first (:forecasts json-tenki))) ;; 天気の画像を取得(今回未使用) (defn tenki-image [forecast] (:url (:image forecast))) ;; (最高気温)/(最低気温) って書式で気温を返してくれる。当然セルシウス度。 (defn tenki-temperature [forecast] (str (:celsius (:max (:temperature forecast))) "/" (:celsius (:min (:temperature forecast))))) ;; main (defn -main [] (let [today (tenki-today (get-tenki))] (println (str "今日の天気: " (:telop today))) (println (str "気温: " (tenki-temperature today))) ))
実行すると、こんな感じになります(2013年5月21日現在)。
$ lein run 今日の天気: 晴時々曇 気温: 27/18
ちゃんと天気を表示してくれます。やったね!
ちょこっとだけ解説。
clj-http を使ってデータを受信した場合、レスポンスの中身を参照するには
(:body (client/get "http://example.com/"))
とします。 client/get がマップ(俗にいう連想配列)になっていて、 :body にデータが入るようになっているためです。
また、 JSON をパースするときには
(json/read-str "{\"a\":1,\"b\":2}" :key-fn keyword)
としました。 :key-fn にkeyword を渡すと、JSON オブジェクトがマップになります。 :key-fn に関数を渡すと、色々といじる事もできるそうですが、まだ試す必要もないので試していません。
さて、天気のデータも取れたので、今度は天気に合わせてアイコンの表示を変えるようなプログラムを作ろうかと思います。