PORTAのAPI使ってみた、けど。

最近、更新してないなーと思ったので、いつもなら記事にしない程度(というか段階)の内容。

いま、蔵書管理のためのWebサービス(SocialtunesLibraryThingみたいなやつだ)を試作してて、書誌情報をどこから取ろうかと考えた結果、amazonを主に、NDL(国立国会図書館)を補助として使うことに決めた。

NDLだけでは最新の図書の書誌情報が得られず、amazonには古い図書の情報が少ないというのが主な理由だ(ほかにもNDLにはシリーズやNDCなんかの情報があったり、書誌情報の信頼性・正確性が高いというのもある)。

もちろんWebcat/Webcat Plusも考えたが、APIとして公開しているものがなく、HTMLからの抽出は、処理の重さや信頼性、あとマナー的にもどうなのということで断念。はやくAPI作ってくださいな・・・。

WorldCatLCも視野に入れたけど、労力の割にそれほどメリットもないので、今回は無視。NDLがWorldCatに情報提供してれば使ったかもなのになあ。

で、amazonのAPI(Amazon Associates Web Service)は超有名なだけあって、簡単に使えた。

PHPのサンプル探してたら、こちらのページがわかりやすかった。

で、今度はNDLがやってる電子リソースポータル「PORTA」(今回はNDLの所蔵データベースしか使わないが)のAPIを使ってみた。※APIについてはPORTAの「このサイトについて」から「外部提供インタフェースについて」で見られる。なんでパーマリンクがないんじゃあ!

なんかSRU(Seach/Retrieval via URL;LCの作った検索プロトコル。URLでリクエストしてXMLでレスポンスがくる)はともかくSRW(SRUのリクエストがSOAP仕様のXMLになったやつ)の情報があまりにも少なくて、なんでSRUを採用しないのかちょっと理解に苦しむところではあるが、まあそれしかないんだから使うしか仕方ない。

で、以下のコードで、一応結果のオブジェクトは返ってくる。

<?php
$client = new SoapClient("http://api.porta.ndl.go.jp/servicedp/services/SRWDp?wsdl");
$q = '(title = architecture) AND (dpid ANY "zomoku zassaku okayama")';
$req = array('version' => '1.1', 'query' => $q,
             'startRecord' => '1', 'maximumRecords' => '200',
             'recordPacking' => 'string', 'recordSchema' => '',
             'sortKeys' => 'title,,1');
$result = $client->searchRetrieveOperation($req);
print_r($result);
?>

しかし、返ってきたデータを見てみると、肝心の書誌情報が入っているrecordDataオブジェクトの中身がなぜか空。ヒット数とかはPORTAのWebで検索したときと同じなので、いいとこまでいってるとは思うんだけどなあ。

ちなみに渡すパラメータが足りないとエラー(java.lang.NullPointerException)が返ってくる。省略可能なのもあるし、仕様書で「設定されない場合」とかあるやつでも省略不能っぽいのもある。

ところで、このAPI、公開されてそこそこ日が経つけど、誰か使ってるんやろか。情報すくないんだよなあ。

ちなみに、今回、開発はWindows上でxamppを走らせてやってます。xamppはApache、PHP5、MySQLやらが一気に使えて(しかもPortable)たいへん便利。ただ、ドライブのルートに配置しないといかんという制限があるので、仮想ドライブを指定するコマンドを書いた、下記のバッチファイルを作ってxammpディレクトリと同じディレクトリに置いて、開発時に実行してます。

rem connect current directory to x: drivesubst x: "%cd%"exit

追記(2008/12/17)

さっき、この追記を書き終えたところで、さあ更新しようと思って、フォームからフォーカス外すために適当なとこクリックしたら、ちょうどそこがリンクになってて、追記分まるまる消えましたよ・・・。もうやる気ないんで、雑な書き方で。箇条書きって楽だなあ。

  • PHPが原因じゃないかとC#で試すもWeb参照でエラー。なんでや。
  • soapUIを発見。試してみるとrecordDataにデータ入ってる!
  • どうもrecordDataは<!CDATA[[]]>に囲まれて返ってくる模様。
  • PHPのSoapClientがレスポンスXMLを配列にする時に落ちてるんかな(参考:xml_parse_into_structを使うと、xmlの中のCDATAが消える -OKWave)。
  • ということは、これが落ちないようにするか、配列にする前のXMLをそのまま取得できればOK。
  • 後者ならsimplexml_load_stringでLIBXML_NOCDATAオプション指定で配列に変換。

まだ最後に書いた解決策のどちらも見つけられてないんですが、また、進展があれば、書きます。

新しく記事起こした場合はこの記事にトラックバックしときます。

追記(2008/12/27)

進展があったのでご報告。ようやく書誌情報にアクセス出来ました。

まず、前の追記に書いていた、配列にする前のXMLを取得する方法がわかった。

SoapClient->__getResponseで最後のレスポンスを文字列で取得できる。てっきりこれも配列で返ってくると思ってたよ。

上のコードの例だと、$client->searchRetrieveOperation($req);のあとに、

$xmlstr = $client->__getRenponse();

で、レスポンスXMLを文字列として取得できる。

こいつをsimplexml_load_stringでCDATAをテキストノードに展開しつつ、配列に変換する。(参考:SimpleXMLでCDATAを取得したいときはLIBXML_NOCDATAを使う - F.Ko-Jiの「一秒後は未来」)

$r = simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA);

これをprint_rで見てみると、

SimpleXMLElement Object ()

あれ?パースエラーかなーなどといろいろ調べてみると、パース自体はできてるけど、ルート要素と名前空間が違う(あるいは名前空間が指定されてる)要素は、SimpleXMLElement->children()で名前空間のURIを指定してアクセスしないといかんらしい。(参考:.☆★ ステレオタイプラボ ★☆. [php]simplexml_load_fileでうまくパース出来ない、なんて事はない。& 正解とお手軽方法)

名前空間を指定する:を別の文字に置換しちゃうという手も魅力的だけど、まあ正攻法でやってみる。

先ほどの$xmlstrをprint_rで見てみると、こんな構成になってる。

(レスポンスされたデータ本体)

よって以下のコードでsearchretrieveresponseにアクセスする。

$srr = $r->children('http://schemas.xmlsoap.org/soap/envelope/')->Body->children('http://www.loc.gov/zing/srw/');

これですべてのレコードにアクセスできるが、個々の書誌情報がはいってるrecordData要素には、書誌情報のXMLがCDATAとして入ってる。このままだとアクセスしにくいので、これも配列に変換する。例では1つめのレコードの書誌情報をrdに入れている。今回はLIBXML_NOCDATAは(たぶん)いらない。

$rd = simplexml_load_string($srr->searchRetrieveResponse->records->record[0]->recordData[0]);

で、さらにこの中身はルート要素と名前空間が違うので・・・

$dc = $rd->children('http://purl.org/dc/elements/1.1/');

で、ようやく書誌情報にまともにアクセスできます。めんどくせー!

で、上記の方法で取得してみたデータのサンプル。(クエリは$q = '(isbn = 4000074628) AND (dpid ANY "zomoku")';に変えてる)

SimpleXMLElement Object(
    [title] => クマムシ?! : 小さな怪物
    [creator] => 鈴木忠‖著
    [description] => Array
    (
        [0] => 本体価格 : 1300円
        [1] => シリーズよみ : イワナミ カガク ライブラリー ; 122
        [2] => シリーズ : 岩波科学ライブラリー ; 122
        [3] => 形態 : 112p ; 19cm
        [4] => 出版地 : 東京
    )
    [publisher] => 岩波書店
)

ほとんどdescriptionにフィールド名とデータをまとめていれちゃってるという、なめてんのかってデータですね(スキーマがdcだからか?また追って調べます。今日はもう疲れた。)。