2012年7月14日土曜日

クライアント向けインターフェースの実装(2)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。好きな言語は?と聞かれたら、Clojureと即答する、たなけんです。本エントリでは、プレゼンテーション層とアプリケーション層とをつなぐ、クライアント向けインターフェースの実装について記載します。

クライアント向けインターフェースの実装(2)

前回リストアップした以下の項目に従い、各関数を修正します。
  • interface-for-clientへのリクエストの処理を追加
  • 関数を引数に取り、抽出結果のJSON文字列を生成する関数の追加
  • 利用APIに対応した抽出関数の追加

interface-for-clientへのリクエストの処理

(def root-url "http://api-pub.dictionary.com/v001")
(compojure-core/defroutes interface-for-client
;
(compojure-core/GET "/dictionary/:word" [word]
(call-api root-url
(list
[:vid (:vid properties)] ["q" word] ["type" "define"] ["site" "dictionary"])
extract-dictionary))
;
(compojure-core/GET "/example/:word" [word]
(call-api root-url
(list
[:vid (:vid properties)] ["q" word] ["type" "example"])
extract-example))
;
(compojure-core/context "/random" []
("/dictionary" []
(call-api root-url
(list
[:vid (:vid properties)] ["type" "random"] ["site" "dictionary"])
extract-random))
("/thesaurus" []
(call-api root-url
(list
[:vid (:vid properties)] ["type" "random"] ["site" "thesaurus"])
extract-random)))
;
(compojure-core/GET "/spelling/:word" [word]
(call-api root-url
(list
[:vid (:vid properties)] ["q" word] ["type" "spelling"])
extract-spelling))
;
(compojure-route/not-found "Page not found"))
view raw core.clj hosted with ❤ by GitHub

urlリソースと関数を関連付けます。例えば、http://localhost/dictionary/testへアクセスすると、引数のwordに"test"が拘束された状態で、call-apiが呼び出されます。

  • compojure.core/defroutesマクロ: urlリソースを定義
  • compojure.core/GETマクロ: http GETメソッドによりアクセスされる節を構成
  • call-api関数: url、パラメータリストおよび抽出関数を引数に取り、JSON文字列を生成


抽出結果のJSON文字列を生成する関数

(defn call-api
[url prms extract-function]
(-> (build-url-with-prms url prms)
(get-body ,)
(extract-function ,)
(json/generate-string ,)))
(defn build-url-with-prms
"to build url string with parameters"
[url prms]
(str url (string/replace-first (apply str (for [[k v] prms] (str "&" (name k) "=" v))) "&" "?")))
(defn get-body
"to send request and get body element of the response"
[url]
(:body (try
(http-client/get url)
(catch java.io.IOException ioe (handle-exception ioe)))))
view raw core.clj hosted with ❤ by GitHub

抽出関数を引数に取り、Dictionary.comから取得したxmlから必要な情報を抽出した結果のJSON文字列を生成します。

  • ->マクロ: 左の関数を評価した結果を右の関数の引数とし、順次関数を実行
  • build-url-with-prms関数: urlパラメータのリストからurl文字列を生成
  • get-body関数: 引数のurlへhttpリクエストを送信し、そのhttpレスポンスのbody要素を取得
  • extract-function(引数): 関数呼び出し時に指定される抽出関数
  • clj-json.core/generate-string関数: clojureオブジェクトをJSON文字列に変換

抽出関数

(defn safety-xpath-call
"to call xpath safely"
[xpath xml]
(try
(xpath/$x xpath xml)
(catch org.xml.sax.SAXException saxe (handle-exception saxe))))
(defn get-result
"to extract text from a xml-string"
[xpath xml-string key-list]
(for [line (safety-xpath-call xpath xml-string)]
(reduce get line key-list)))
(defn- get-query-word
"to extract query word from a xml-string"
[xml-string]
(first (get-result "(/*)[1]" xml-string '(:attrs :query))))
(defn extract-dictionary
"to extract word and entries from a xml-string of thesaurus"
[xml-string]
{:word (get-query-word xml-string)
:entries
(flatten
(for [pos (get-result "//partofspeech" xml-string '(:attrs :pos))]
(for [line (get-result (str "//partofspeech[@pos=\"" pos "\"]/defset/def") xml-string '(:text))] {:pos pos :text line})))})
(defn extract-example
"to extract word and entries from a xml-string of example"
[xml-string]
{:word (get-query-word xml-string)
:entries (get-result "//example" xml-string '(:text))})
(defn extract-random
"to extract word from a xml-string of random"
[xml-string site]
{:word (first (get-result (str "//" site "/random_entry") xml-string '(:text)))})
(defn extract-spelling
"to extract word and entries from a xml-string of spelling"
[xml-string]
{:word (get-query-word xml-string)
:entries (get-result "//suggestion" xml-string '(:text))})
view raw core.clj hosted with ❤ by GitHub

xpathによりxmlからノードを取得し、さらにそこから指定した要素を抽出します。

  • safety-xpath-call関数: xpathによりxmlからノードを取得する。指定したxpathが取得出来なかった場合、handle-exception関数を呼び出す
  • get-result関数: safety-xpath-call関数により取得したxmlノード(ネストした状態のハッシュ
  • )から、順にキーを指定して、求める値を取得する
  • get-query-word関数: xml内に含まれる、問い合わせ単語を取得する。具体的にはxpathが(/*)[1]のノードから、キー:attrs :queryの値を取得する。
  • extract-dictionary関数: 英英辞書APIから取得したxmlから、問い合わせ単語と定義を抽出する。
  • extract-example関数: 例文辞書APIから取得したxmlから、問い合わせ単語と例文を抽出する。
  • extract-random関数: ランダムAPIから取得したxmlから、単語を抽出する。
  • extract-spelling関数: 綴り時APIから取得したxmlから、問い合わせ単語と綴り字の候補を抽出する。





今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん (作業時間120分)






0 件のコメント:

コメントを投稿