Subscribed unsubscribe Subscribe Subscribe

SchemeでYahoo!検索Webサービス 2

プログラミング

昨日の続き.

以下の変更を加えた.

  • gauche.netモジュールでGETしていたのを,より高レベルのrfc.httpモジュールのhttp-getに変更.
  • sxml.ssax,sxml.sxpathモジュールを使って返ってきたXMLを処理するAPIを多少追加.
  • RESTリクエストのオプショナルな引数に対応.

gauche.net -> rfc.http

より高レベルのインタフェースがあったので,get関数を変更した.コードがシンプルになって良い.

以前のコード.

(call-with-client-socket
  (make-client-socket 'inet host 80)
  (lambda (in out)
    (format out "GET ~a HTTP/1.0\r\n" path)
    (format out "HOST: ~a\r\n\r\n" host)
    (flush out)
    (port->string in)))

変更後のコード.

(receive (status header body)
         (http-get host path)
         (list status header body)))))

status,header,bodyに分けて返してくれるので非常に扱いやすい.

sxml.ssax,sxml.sxpathでXMLをごにょごにょ

これはまだ完成していない.とりあえず作ったのは検索結果の件数などを返す部分.

(define (result-body result)
  (string->sxml (caddr result)))

(define (string->sxml string)
  (call-with-input-string string
    (lambda (in)
      (ssax:xml->sxml in '()))))

(define (root-node result)
  ((sxpath '(urn:yahoo:jp:srch:ResultSet))
           (result-body result)))

(define (total-results-returned result)
  (sxml:number ((sxpath '(@ totalResultsReturned))
                (root-node result))))
(define (total-results-available result)
  (sxml:number ((sxpath '(@ totalResultsAvailable))
                (root-node result))))
(define (first-result-position result)
  (sxml:number ((sxpath '(@ firstResultPosition))
                (root-node result))))

検索結果はこんな感じで取り出すことができるけど,もっと綺麗に書けないものか.

(define (func result)
  ((sxpath '(urn:yahoo:jp:srch:Result))
   (root-node result)))

オプショナルな引数に対応

ドキュメントにある通り,typeやsiteなどいくつかの引数を使うことができる.Schemeでこの機能を利用するにはキーワード引数がよい.

ということで以前の手抜き関数make-method

(define (make-method appid query)
  (format "webSearch?appid=~a&query=~a" appid query))

を以下のように変更する.

(define (make-method appid query options)
  (let ((base-method (format "webSearch?appid=~a&query=~a"
                             appid query)))
    (define (add-options method options)
      (if (null? options)
          method
          (add-options (format "~a&~a" method
                               (option->string
                                 (car-options options)))
                       (cdr-options options))))
    (define (car-options options)
      (cons (car options) (cadr options)))
    (define (cdr-options options) (cddr options))
    (define (option->string option)
      (format "~a=~a"
              (keyword->string (car option))
              (cdr option)))
    (add-options base-method options)))

キーワード引数の解析にはlet-keywords*を用いるのが普通のようだけど,値なしの引数をどう表現したらいいのかわからなかったので,自前でやってしまった.キーワードが間違っていたり,値が間違っていたときのエラー処理は全く書いていない.

その他

コードはGoogle Page Creatorでページを作ってそこにあげることにする.

もっと良いインタフェースがありそうな気がするが,あんまり使い道がないので浮かばない.ここでさくっとgauche-gtkでクライアントを作ってみて検証してみたいところだが,自宅PCのGTK+が新しすぎるためか,gauche-gtkのインストールでこけて使えないのでパス.

それからエラー処理を全く書いていないので,何とかしなくては.

今後は,検索結果のリストがストリームになってたりしたら面白そうな気がするので,そっちの方向を探ってみようかな.

TODO: 忘れそうなのでメモ

  • コードを置いておくページの作成.
  • 各エントリの取得APIなどの実装.
  • 画像検索などにも対応?
  • エラー処理
  • ストリームに対応?

こんなもんだろうか.