PHPで国立国会図書館を検索

(1/1)
PHPで「国立国会図書館サーチ」を利用し、書籍を検索するプログラムを作ってみる。また、「PHPでISBNコードをASINコードに変換する」を利用し、検索結果をAmazonにリンクさせる。

また、「C++で国立国会図書館検索」では、このプログラムをWindowsアプリに移植したので参考にされたい。

(2024年3月9日)API 1.1版に対応,pahooInputData導入

目次

サンプル・プログラムの実行例

PHPで国立国会図書館を検索

サンプル・プログラム

圧縮ファイルの内容
searchNDL.phpサンプル・プログラム本体。
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
searchNDL.php 更新履歴
バージョン 更新日 内容
1.4.0 2024/03/09 API 1.1版に対応,pahooInputData導入
1.31 2021/01/18 ISBN検索時に情報不足になることがあり回避策追加
1.3 2021/01/06 PHP8対応,エラー処理の厳格化
1.2 2021/01/05 書名読みがな追加,一覧表スタイル変更
1.1 2017/04/08 PHP7対応
pahooInputData.php 更新履歴
バージョン 更新日 内容
1.5.0 2024/01/28 exitIfExceedVersion() 追加
1.4.2 2024/01/28 exitIfLessVersion() メッセージ修正
1.4.1 2023/09/30 コメントの訂正
1.4.0 2023/09/09 $_GET, $_POST参照をfilter_input()関数に置換
1.3.0 2023/07/11 roundFloat() 追加

WebAPI:国立国会図書館サーチ(OpenSearch)

WebAPI
URL
https://ndlsearch.ndl.go.jp/api/opensearch
入力パラメータ
フィールド名 要否 内  容
title いずれか 書名、記事名など。UTF-8エンコード。部分一致。
creator いずれか 著者、編者など。UTF-8エンコード。部分一致。
publisher いずれか 出版社。UTF-8エンコード。部分一致。
ndc いずれか NDC分類。前方一致。
from 任意 検索を開始する出版年月日。YYYY-MM-DD。
until 任意 検索を終了する出版年月日。YYYY-MM-DD。
cnt 任意 取得する検索結果の件数。省略時は200。一度に取得できる最大件数は500。
isbn いずれか ISBNコード。10桁または13桁。前方一致。
mediatype 任意 資料種別
“bools”:図書
“periodicals”:雑誌
“articles”:記事
“newspapers”:記事
その他は「データグループ ID・mediaType 一覧」参照
応答データ構造(xml) rss channel title 検索結果タイトル link リクエストURL description 検索結果メモ language 言語 item title タイトル link 国会図書館内URL description 内容 author 作者 category 分類 guid 国会図書館内URL pubDate 出版日 dc:title タイトル dcndl:titleTranscription タイトル(読みがな) dcndl:volume 巻数 dcndl:seriesTitle シリーズ・タイトル dc:publisher 出版社 dc:identifier ISBN dc:identifier JPNO dc:subject NDC item title 繰り返し link ...

解説:初期値設定

  15: define('INTERNAL_ENCODING', 'UTF-8');
  16: mb_internal_encoding(INTERNAL_ENCODING);
  17: mb_regex_encoding(INTERNAL_ENCODING);
  18: define('MINUMUM_VERSION', '5.0.0');
  19: if (! defined('MYSELF')) {
  20:     if (isset($_SERVER['SCRIPT_NAME'])) {
  21:         define('MYSELF', basename($_SERVER['SCRIPT_NAME']));
  22:     } else if (isset($_SERVER['PHP_SELF'])) {
  23:         define('MYSELF', basename($_SERVER['PHP_SELF']));
  24:     } else {
  25:         define('MYSELF', basename(__FILE__));
  26:     }
  27: }
  28: define('REFERENCE', 'https://www.pahoo.org/e-soul/webtech/php06/php06-37-01.shtm');
  29: define('TITLE', '国立国会図書館サーチ');
  30: 
  31: //データ入力に関わる関数群:include_pathに配置すること
  32: require_once('pahooInputData.php');
  33: 
  34: //PHPバージョン・チェック
  35: exitIfLessVersion(MINUMUM_VERSION);
  36: 
  37: //リファラチェック+リリースフラグの設定
  38: if (isset($_SERVER['HTTP_HOST']) && ($_SERVER['HTTP_HOST'] == 'localhost')) {
  39:     define('FLAG_RELEASE', FALSE);
  40:     define('REFER_ON', '');
  41:     ini_set('display_errors', 1);
  42:     ini_set('error_reporting', E_ALL);
  43: else {
  44:     //リリース・フラグ(公開時にはTRUEにすること)
  45:     define('FLAG_RELEASE', TRUE);
  46:     //リファラ・チェック(直リン防止用;空文字ならチェックしない)
  47:     if (! isCommandLine()) {
  48:         define('REFER_ON', 'www.pahoo.org');
  49:     } else {
  50:         define('REFER_ON', '');
  51:     }
  52: }
  53: 
  54: //入力バリデーション
  55: define('QUERY_MIN',  2);        //検索文字列の最短
  56: define('QUERY_MAX', 40);        //検索文字列の最長
  57: 
  58: //表示幅(ピクセル)
  59: define('WIDTH', 600);
  60: 
  61: //TRUE:書名読みがなを表示する/FALSE:表示しない
  62: define('RUBY', TRUE);
  63: 
  64: //国立国会図書館サーチAPI 1.1(変更不可)
  65: define('NDL_URL', 'https://ndlsearch.ndl.go.jp/api/opensearch');

いくつかのパラメータを定数に定義している。変更不可としている以外の定数は自由に設定できる。
定数 RUBY は、書名読みがな(応答データの dcndl:titleTranscription 要素の内容)をrubyタグを使って表示するか否かのフラグである。

解説:リクエストURL取得

 251: /**
 252:  * 国立国会図書館サーチAPI のURLを取得する
 253:  * @param   string $query   タイトル(UTF-8;部分一致)
 254:  *                         またはISBN(10桁または13桁;完全一致または前方一致)
 255:  *                         【省略不可】
 256:  * @param   string $creater 作成者(UTF-8;部分一致)
 257:  * @param   string $from    開始出版年月日(YYYY-MM-DD)
 258:  * @param   string $until   終了出版年月日(YYYY-MM-DD)
 259:  * @param   int    $cnt     出力レコード上限値(省略時=50)
 260:  * @param   string $mediatype 資料種別(省略時=すべて)
 261:  * @return  string WebAPI URL
 262: */
 263: function getURL_searchNDL($query, $creater='', $from='', $until='', $cnt=50, $mediatype='') {
 264:     $isbn = '';
 265:     if (preg_match('/^[0-9|\-]+$/', $query) == 1) {
 266:         $title = '';
 267:         $isbn = 'isbn=' . preg_replace('/\-/', '', $query);
 268:     }
 269:     if ($isbn == '') {
 270:         $title = 'title=' . urlencode($query);
 271:     }
 272: 
 273:     $creater = ($creater !''? '&creater=' . urlencode($creater: '';
 274:     $from    = ($from !'')    ? '&from=' . $from : '';
 275:     $until   = ($until !'')   ? '&until=' . $until : '';
 276:     $cnt     = ($cnt > 0)       ? '&cnt=' . $cnt : '';
 277:     $mediatype = ($mediatype !''? '&mediatype=' . $mediatype : '';
 278: 
 279:     return NDL_URL . '?' . $title . $isbn . $creater . $from . $until . $cnt . $mediatype;
 280: }

ユーザー関数 getURL_searchNDL は、タイトル、作成者、開始出版年月日、終了出版年月日、出力レコード上限値、資料種別からリクエストURLを返す。
タイトルには、書名とISBNのいずれかを指定可能だ。ユーザー関数内で、数値とハイフンならばISBNとして認識する。
また、タイトル以外は省略可能にしてある。

解説:国立国会図書館検索

 282: /**
 283:  * 国立国会図書館サーチAPIを呼び出し結果を配列に格納する
 284:  * @param   array  $items   書籍情報格納用
 285:  * @param   string $errmsg  エラーメッセージ格納用
 286:  * @param   string $query   タイトル(UTF-8;部分一致)
 287:  *                         またはISBN(10桁または13桁;完全一致または前方一致)
 288:  *                         【省略不可】
 289:  * @param   string $creater 作成者(UTF-8;部分一致)
 290:  * @param   string $from    開始出版年月日(YYYY-MM-DD)
 291:  * @param   string $until   終了出版年月日(YYYY-MM-DD)
 292:  * @param   int    $cnt     出力レコード上限値(省略時=50)
 293:  * @param   string $mediatype 資料種別(省略時=すべて)
 294:  * @return  int 検索結果の件数
 295: */
 296: function searchNDL(&$items, &$errmsg, $query, $creater='', $from='', $until='', $cnt=50, $mediatype='') {
 297:     //名前空間
 298:     define('NS_DCMITYPE', 'http://purl.org/dc/dcmitype/');
 299:     define('NS_RDFS', 'http://www.w3.org/2000/01/rdf-schema#');
 300:     define('NS_XSI', 'http://www.w3.org/2001/XMLSchema-instance');
 301:     define('NS_OPENSEARCH', 'http://a9.com/-/spec/opensearchrss/1.0/');
 302:     define('NS_DC', 'http://purl.org/dc/elements/1.1/');
 303:     define('NS_DCNDL', 'http://ndl.go.jp/dcndl/terms/');
 304:     define('NS_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
 305:     define('NS_RCTERMS', 'http://purl.org/dc/terms/');
 306: 
 307:     $errmsg = '';
 308:     $url = getURL_searchNDL($query, $creater, $from, $until, $cnt, $mediatype);
 309: 
 310:     $xml = @simplexml_load_file($url);
 311:     if ($xml == FALSE) {
 312:         $errmsg = '国立国会図書館サーチAPIの接続に失敗しました.';
 313:         return FALSE;
 314:     }
 315:     //レスポンス・チェック
 316:     $count = @count($xml->channel->item);
 317:     if ($count <0) {
 318:         $errmsg = '検索結果がありません.';
 319:         return (-1);
 320:     }
 321:     $cnt = 0;
 322:     foreach ($xml->channel->item as $item) {
 323:         //ISBN,書名,著者,出版社,NDC番号,URL,出版日
 324:         $node = $item->children(NS_DC);
 325:         $isbn = '';
 326:         foreach ($node->identifier as $id) {
 327:             if (preg_match('/ISBN/iu', (string)$id->attributes(NS_XSI)) == 1) {
 328:                 $isbn = (string)$id;
 329:             }
 330:         }
 331:         if ($isbn == '')    continue;
 332:         if ((string)$node->title !'') {
 333:             $items[$isbn]['title'] = (string)$node->title;
 334:         } else if (! isset($items[$isbn]['title'])) {
 335:             $items[$isbn]['title'] = '';
 336:         }
 337:         if ((string)$node->creator !'') {
 338:             $items[$isbn]['author']    = (string)$node->creator;
 339:         } else if (! isset($items[$isbn]['author'])) {
 340:             $items[$isbn]['author'] = '';
 341:         }
 342:         if ((string)$node->publisher !'') {
 343:             $items[$isbn]['publisher'] = (string)$node->publisher;
 344:         } else if (! isset($items[$isbn]['publisher'])) {
 345:             $items[$isbn]['publisher'] = '';
 346:         }
 347:         $items[$isbn]['NDC'] = '';
 348:         foreach ($node->subject as $id) {
 349:             if (preg_match('/NDC/iu', (string)$id->attributes(NS_XSI)) == 1) {
 350:                 $items[$isbn]['NDC'] = (string)$id;
 351:             }
 352:         }
 353:         if ((string)$item->link !'') {
 354:             $items[$isbn]['url'] = (string)$item->link;
 355:         } else if (! isset($items[$isbn]['url'])) {
 356:             $items[$isbn]['url'] = '';
 357:         }
 358:         if ((string)$item->pubDate !'') {
 359:             $items[$isbn]['pubDate'] = (string)$item->pubDate;
 360:         } else if (! isset($items[$isbn]['pubDate'])) {
 361:             $items[$isbn]['pubDate'] = '';
 362:         }
 363:         //巻数,書名読みがな
 364:         $node = $item->children(NS_DCNDL);
 365:         if ($node->volume !'') {
 366:             $items[$isbn]['title'] = $items[$isbn]['title'. '(' . (string)$node->volume . ')';
 367:         }
 368:         $str = (string)$node->titleTranscription;
 369:         $str = preg_replace('/[  ]/ui', '', $str);     //空白除去
 370:         $str = mb_convert_kana($str, 'c');      //カタカナ→ひらがな変換
 371:         $items[$isbn]['yomi'] = $str;
 372:         $cnt++;
 373:     }
 374: 
 375:     return $cnt;
 376: }

ユーザー関数 searchNDL は国立国会図書館サーチAPI呼び出し、検索結果を配列 $items に格納し、検索結果の件数を返す。
サンプル・プログラムでは、引数 $query にタイトルまたはISBNを渡すことで検索を行う。$creater 以降の引数はデフォルト値のままにしてあるが、ぜひ、これらの引数を利用したプログラムを作ってみてほしい。

検索結果のXML構造はRSS 2.0に似ており、PHP5(SimpleXML)では名前空間に注意が必要だ。名前空間については「PHPでコロンを含むXML要素名を扱う方法」を参照のこと。ここでは、各々の名前空間を定数で定義している。

検索結果のISBNからASINを求めAmazonへのリンクを張る部分は、「PHPでISBNコードをASINコードに変換する」のサンプル・プログラムを流用している。

エラーが発生した場合、引数 $errmsg にエラーメッセージを格納する。エラーがなければ空文字を代入する。
これら以外の部分は、いままで紹介したプログラムと同じである。

質疑応答

【質問】
「PHPで国立国会図書館を検索」のページ大変参考になります。使用させていただきたいと思っています。
ところで、本のタイトルの読みはXMLでは <dcnl:titleTranscription> とあるのですが、上記のPHPでフリガナの取得はできないのでしょうか。どのようにすれば可能なのでしょうか?教えていただけませんか。
本のサイズ<extent>は何とか取得することができたのですが。
<dc;title>などと <dcnl:titleTranscription> などとの記述の違いが判りません。
教えていただけるとありがたいのですが。
【回答】
お気づきのように、WebAPIの応答にある <dcnl:titleTranscription> に書名の読み仮名(全角カタカナ)が入っています。
読みがなを含めて取得・表示するようプログラムを改良しました。お試しください。
【質問】
ルビ入りのプログラムを作成くださりありがとうございます。参考にさせていただきます。
今後ともよろしくお願いいたします。
【回答】
どういたしまして😀
ご活用ください。
【質問】
たびたびお世話になります。
貴重なプログラムなので活用させていただいています。
「鬼滅の刃」を検索すると著者名まで表示されるのですが、その中の1つのISBNで検索してみると、それでは著者名が表示されません。
どうしてそのような違いが生じるのか、よくわかりません。はじめはそのデータが登録されていないのかと同様のことをいろいろやってみても同じような状況になります。コミックだからでしょうか。
author creator 違いなのかと代えてもみても、うまくいきません。
authorを使用するところとcreatorを使用する個所とがあるのでしょうか。
【回答】
ISBNで検索する場合、ISBNが単一(1つの書籍)であるにもかかわらず、複数の結果が還ってくることがあります。どうやら国立国会図書館サーチの仕様のようです。
そこで、複数の結果が返ってきたときは、一番最後の有効な値を表示するようにプログラムを改良しました。
ここで、「ISBN=9784088812830」(『鬼滅の刃』第9巻)を検索すると、書名に「遊郭潜入大作戦」と表示されます。これは、国立国会図書館サーチが返す複数の結果の最後が、書名にサブタイトルが入っているためです。いまのところ、書名なのかサブタイトルなのかを判断する情報がないため、プログラムの改良はここまでとします。

参考サイト

(この項おわり)
header