2009年1月21日

Yahoo!みんなの検定

「検定詳細API」を使って問題を表示してみよう!

  • このエントリーをはてなブックマークに追加
Yahoo!みんなの検定ProjectのK.K.です。

前回、【「三国志」に関する検定を表示し、受験する】という
機能を作成するため、検定リストAPIを使うということを説明しました。

今回は、「検定詳細API」を使って、問題を表示してみましょう。

ひとまず、表示する内容を

・「三国志」のキーワードを持つ
・作成された最新の検定から
・ランダムで1問表示する

に絞ってみましょう。

では、PHPでのサンプルを使って説明していきます。
APIのレスポンスとして返ってくるXML。
これのパース方法は、PHP5では「SimpleXML関数」が強力なのですが、
PHP4でも動くPEARの「XML_Unserializer」ライブラリを使用しています。

<?php
require_once 'XML/Unserializer.php';

// みんなの検定APIの基本URL
$API_BASE_URL = 'http://cert.yahooapis.jp/MinnaCertWebService/V1/';

// APP_ID
$APP_ID = '{あなたのAPP_ID}';

// 指定するキーワード
$KEYWORD = '三国志';

// 検定一覧APIのURL(order=1:公開日の降順 amount=1:1件取得)
$LIST_API_URL = $API_BASE_URL . 'certList?' . http_build_query(
    'appid' => $APP_ID,
    'order' => 1,
    'amount' => 1,
    'keyword' => $KEYWORD
);

// 検定詳細APIのURL(get_q=2:問題情報+正解と解説を取得)
$DETAIL_API_URL = $API_BASE_URL . 'certDetail?' . http_build_query(
    'appid' => $APP_ID,
    'get_q' => 2
    'cert_id' => null
);

/* 
 *
 * XMLのパース
 *
 */

// XMLパース用クラス作成
$class_xml_uns = new XML_Unserializer(array('parseAttributes' => true));

// 検定一覧XMLのパース実行
$class_xml_uns->unserialize(file_get_contents($LIST_API_URL));

// パース結果を配列に格納
$res_list = $class_xml_uns->getUnserializedData();

これで「三国志」のキーワードを持つ最新の検定の情報を取得し、
検定に個別に割り振られている「検定ID」を抽出することができるようになりました。
/*
 * 検定の各情報を抽出
 */

// 検定の詳細を取得
$ary_cert = $res_list['Result'];

// 検定ID抽出
$cert_id = $ary_cert['CertId'];

// 検定名抽出
$cert_name = mb_convert_encoding($ary_cert['CertName'], 'EUC-JP', 'UTF-8');

// 検定のURLを抽出
$cert_url = $ary_cert['CertDetailPcUrl'];


ランダムに1問だけ表示したいですが、検定によって問題数が5問〜8問までさまざまです。
問題数を示す「QuestionCount」を抽出して、その中から何問目かをランダムで取得するようにしましょう。

// 検定の中からランダムに1問取得する
$order_number = mt_rand(1, $ary_cert['QuestionCount']);

検定IDと、何問目を取得するかを抽出できたので、
これをもとに検定詳細APIを呼び出し、パースします。

// 抽出したIDで指定した検定の詳細XMLのパース実行
$class_xml_uns->unserialize(file_get_contents($DETAIL_API_URL . $cert_id . "&order_number=" . $order_number));

// パース結果を配列に格納
$res_detail = $class_xml_uns->getUnserializedData();
$ary_detail = $res_detail['Result']['QuestionResult']['QuestionData'];

// 問題文抽出
$question_text = mb_convert_encoding($ary_detail['QuestionText'], 'EUCJP-WIN', 'UTF-8');
$question_text = str_replace("\n" ,"<br>", $question_text);

// 選択肢抽出
$choice = '';
foreach ($ary_detail['ChoicesResult']['ChoiceData'] as $ary_choice ) {
    $choice_number = $ary_choice['OrderNumber'];
    $choice_text = mb_convert_encoding($ary_choice['ChoiceText'], 'EUCJP-WIN', 'UTF-8');

    $choice .=  '(' . $choice_number . ')' . $choice_text . '<br>';
}

// 正解抽出
$answer = $ary_detail['CorrectAnswer'];

// 解説抽出
$explanation = mb_convert_encoding($ary_detail['QuestionExplanation'], 'EUCJP-WIN', 'UTF-8');
if ( $explanation == '' ) {
    $explanation = '※解説はありません';// 解説は必須ではないので空の場合あり
} else {
    $explanation = str_replace("\n", '<br>', $explanation);
}


このようにして、問題表示に必要そうな情報を取得することができました。
これを使っていろいろなことができそうですが、
とりあえずシンプルに表示だけしてみます。


/** 
 * HTML部分作成
 * とりあえず、「答えを見る」ボタンを押すと、
 * 折りたたんである答えが表示されるだけのシンプルなもの。
 */

// 問題部分のHTMLを作成
$question_html = <<<_HTML_
${cert_name}<br>
<br>
${question_text}<br>
<br>
[ 選択肢 ]<br>
${choice}

_HTML_;

// 解答部分のHTMLを作成
$answer_html = '[ 正解 ] (' . $answer .  ')<br>[ 解説 ]' . $explanation .  
    '<br><a href="' . $cert_url . '" target="_brank">ほかの問題も解いてみる</a>';	

準備完了。htmlとして表示します。
<html>
 <head>
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
  <title>サンプル</title>
 </head>
 <body>
  <?php echo $question_html ?>
  <form>
   <input type="button" id="answer" value="答えを見る" onClick="answerOn();">
   <script type="text/javascript">
    function answerOn() {
     var answer = '<?php echo $answer_html ?>';
     document.getElementById("result").innerHTML = answer;
    }
   </script>
  </form>
  <div id="result"></div>
 </body>
</html>

今回は1問だけランダムで取得してきましたが、全問取得したり、
複数の検定からまたいで問題を取得したりと応用できますので、
あっと驚くような使い方を期待してます。

なお、検定には「何問中何問以上で合格」といった基準や
正解数に応じて評価メッセージが設定されているものもあります。


検定の解答結果から、その評価を返す「検定受験API」も、
また紹介していこうと思います。

受けて作ってつながろう!
Yahoo!みんなの検定

Yahoo! JAPANでは情報技術を駆使して人々や社会の課題を一緒に解決していける方を募集しています。詳しくは採用情報をご覧ください。

  • このエントリーをはてなブックマークに追加