楽天ジャンル検索で動的にセレクトボックス生成

Posted by joeartsea on 2009-03-31

JavaScriptでセレクトボックスの連動をもとにアマゾンと楽天のカテゴリが連動するセレクトボックスを作ります。アマゾンは静的にしかセレクトボックスのオプションアイテムを渡せませんが、楽天ウェブサービス(Rakuten Web Service)では楽天ジャンル検索APIというのがあって楽天にリクエストを渡せば現在のジャンルを返してくれます。活用すればジャンル名やジャンルコードの変更が生じてもメンテナンスフリーな画面が作れます。

レスポンスはXML形式とJSON形式を選べますがJavaScriptでセレクトボックスの連動をもとにするのでJavaScriptと相性のいいJSON形式にします。JSONのデータを見る場合はブラウザのURL欄に以下のURLを入力してアクセスします。ブラウザの画面にサーバから返されたデータが表示されます。[YOUR_developerID]のところはご自分で取得した楽天デベロッパーIDが入ります。

1
http://api.rakuten.co.jp/rws/2.0/json?developerId=[YOUR_developerID]&operation=GenreSearch&version=2007-04-11&genreId=0

ということはHTML内に以下のように書くだけでデータを取得し、後はセレクトオプションのアイテムに加工するだけで完成してしまうんじゃないんでしょうか?

1
<script type="text/javascript" src="http://api.rakuten.co.jp/rws/2.0/json?developerId=[YOUR_developerID]&operation=GenreSearch&version=2007-04-11&genreId=0"></script>

さすがにそこまで簡単ではありません。実際にはJSONPという手法が必要です。JSONPとはJSONデータを受け取った後の処理(関数)を先に記述しておき、読み込むJSONデータをその関数でラップする手法です。いわゆるコールバック関数というのを使います。言葉で説明してもよくわからないと思いますので実際に試してみましょう。

楽天ウェブサービス(Rakuten Web Service)ではJSONPにも対応しています。先ほどのJSONデータを受け取ったリクエストパラメータに「callBack=関数名」を追加します。これでJSONデータを読み込んだ後に実行される関数を指定できます。試しに以下のように「callBack=cb」を追加してブラウザでアクセスしてみましょう。

1
http://api.rakuten.co.jp/rws/2.0/json?developerId=[YOUR_developerID]&operation=GenreSearch&version=2007-04-11&genreId=0&callBack=cb

すると返ってくるJSONデータがcb(…)の中に入った形になっています。次に以下のようなソースを書きcb関数を実装します。とりあえず最初のアイテムのジャンル名をalertで表示する簡単な処理にしました。実行するとダイアログに「CD・DVD・楽器」と表示されるはずです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>
<title>Test</title>
<script type="text/javascript">
<!--
function cb(json)
{
alert(json.Body.GenreSearch.child[0].genreName);
}
-->
</script>
</head>
<body>
<script type="text/javascript" src="http://api.rakuten.co.jp/rws/2.0/json?developerId=[YOUR_developerID]&operation=GenreSearch&version=2007-04-11&genreId=0&callBack=cb"></script>
</body>
</html>

これを応用して以下のように書けば楽天のカテゴリだけ動的に読み込める画面が完成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>
<title>Test</title>
<script src="prototype.js" type="text/javascript"></script>
<script src="common.js" type="text/javascript"></script>
<script>
<!--
addEvent(window, &#39;load&#39;, init, false);
function init()
{
addEvent($("form1").webapi, &#39;change&#39;, setMenuItem, false);
setMenuItem();
}
function setMenuItem()
{
var api_key = &#39;[YOUR_developerID]&#39;;
var url = &#39;http://api.rakuten.co.jp/rws/2.0/json&#39;
+ &#39;?operation=GenreSearch&version=2007-04-11&genreId=0&callBack=setItem&&#39;
+ &#39;developerId=&#39; + api_key;
var script = document.createElement(&#39;script&#39;);
script.type = &#39;text/javascript&#39;;
script.charset = &#39;utf-8&#39;;
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
function setItem(json)
{
var menuItem = {
"Aws": [
{"genreId": "Blended", "genreName": "すべて"},
{"genreId": "Books", "genreName": "和書"},
{"genreId": "ForeignBooks", "genreName": "洋書"},
{"genreId": "Electronics", "genreName": "エレクトロニクス"},
{"genreId": "Kitchen", "genreName": "ホーム&キッチン"},
{"genreId": "Music", "genreName": "ミュージック"},
{"genreId": "MusicTracks", "genreName": "曲名"},
{"genreId": "Classical", "genreName": "クラシック音楽"},
{"genreId": "DVD", "genreName": "DVD"},
{"genreId": "VHS", "genreName": "VHS"},
{"genreId": "Video", "genreName": "ビデオ"},
{"genreId": "Software", "genreName": "ソフトウェア"},
{"genreId": "VideoGames", "genreName": "ゲーム"},
{"genreId": "Toys", "genreName": "おもちゃ"},
{"genreId": "Hobbies", "genreName": "ホビー"},
{"genreId": "SportingGoods", "genreName": "スポーツ&アウトドア"},
{"genreId": "HealthPersonalCare", "genreName": "ヘルス&ビューティー"},
{"genreId": "Watches", "genreName": "時計"},
{"genreId": "Baby", "genreName": "ベビー&マタニティ"},
{"genreId": "Apparel", "genreName": "アパレル"}
],
"Rws": json.Body.GenreSearch.child
};
//初期化
var option_cnt = $("form1").category.options.length;
for(var i = 0; i < option_cnt; i++)
{
$("form1").category.remove(0);
}
var n = $F("webapi");
for(var i = 0; i < menuItem[n].length; i++)
{
$("form1").category.options[i] = new Option(menuItem[n][i]["genreName"], menuItem[n][i]["genreId"]);
}
}
-->
</script>
</head>
<body>
<form id="form1">
<select id="webapi" name="webapi">
<option value="Aws">アマゾン</option>
<option value="Rws">楽天</option>
</select>
<select id="category" name="category">
</select>
</body>
</html>