アンケート/質問システム
QuestionServletについて


1.概要

このシステムは、XMLファイルに質問/選択肢/回答/その後のジャンプ先等を記述することで、その時点における適切なフォーマッティングを行うものです。
考えられる使用例として、以下のようなものがあります。


2.機能一覧(特徴)

将来検討中機能

処理概要


3.実行方法

必要環境

Servlet実行環境 Cocoonを用いるためApache+Jservが良いと思われますが、他の環境でもCocoon.jar/openxml.jarあたりがあれば大丈夫かな?
→参考:Java Apache Project
JSP 必須ではありません。あれば最終結果の出力が楽になります。最終結果がHTMLでよいような場合には要らないです。
→参考:GNUJSPThe Jakarta Project
XML parser 最新版ではJAXPを同梱しています。1.0βまではXML Parser for Javaに依存していました。
  1. initArgにproperties=プロパティファイルパスを指定します。
    プロパティファイルについてはインストールページ参照。
  2. http://host/servlets/question?file=question.xml というようにfileパラメタを伴ってServletを呼び出します。
    他に付加可能なパラメタとして以下のようなものがあります。

    id 質問のID。<question>要素のid属性の値。省略するとファイル中の先頭の<question>が対象となる。
    stylesheeturl 外部スタイルシートのURL。
    grouping "off"で<group>要素を無視して、指定された一つの質問のみを表示する。
    lf "list"で、選択肢をリストボックス表示します。"ddlist"で選択肢をドロップダウンリストで表示します。"nobreak"で選択肢のラジオボタンを横並びにします。

4.XMLファイルの構文

DOCUMENTTYPE [questions] に基本的に従う必要があります。(DTDはこちら)
要素の意味はDTDファイルに記述してあります。
注意:このDTDをもとに検証を行おうとしても無理です。現状はDTDにHTML要素が定義されていないので、検証パーザでは通らないことになります。単なるガイドラインと考えてください。

プロトタイプです。まだ仕様は確定していませんし、改善の余地が多くあります。

以下にXMLの指定例を記します。

<?xml version="1.0" encoding="ISO-2022-JP"?>

<questions>
    <!-- このファイルの質問群についてのタイトル。-->
    <!-- タイトルバーに表示されます。 -->
    <title>サンプル質問集(ネタが無い・・・)</title>

    <!-- もし、複数の質問を一度に表示したい場合は、 -->
    <!-- [group]要素で複数の[question]要素を囲みます。 -->


    <!-- 一つの質問を表す要素。 -->
    <!-- id属性は質問を識別する文字列。先頭であれば省略可 -->
    <!-- 質問に答えるまでの制限時間を設ける事が出来ます。 -->
    <!-- セッション単位で有効です。単位は秒。0で無制限。省略時0 -->
    <question id="1" timelimit="0">
        <!-- その質問のタイトルまたは質問番号。省略可。 -->
        <title>質問:1-1</title>

        <!-- 質問文。図等を使う場合は内部にHTML要素を記述できますが、 -->
        <!-- XMLの文法に合う形で!!!例:  <br> -> <br/>                -->
        <content>
            <em>Windows</em>の未来についてどう思いますか?
        </content>

        <!-- 選択形式の場合に使います。いわゆるラジオボタン -->
        <!-- shuffle属性があると(値は何でもよい)表示時に -->
        <!-- 各項目の順番はばらばらになります。 -->
        <select shuffle="true">
            <!-- ここでのid属性は省略不可 -->
            <item value="1" score="-5">
                <!-- 選択項目本文。内部にHTML要素を記述できますが、 -->
                <!-- XMLの文法に合う形で!!!例:  <br> -> <br/> -->
                <content>
                    後10年は世界中で使われるでしょう。
                </content>
                <!-- 選択した項目ごとに飛び先と重みを付けたい場合 -->
                <!-- ここでnextfile/nextidを省略すると、質問ノード上の -->
                <!-- nextfile/nextidが使われます -->
                <nextfile>question1.xml</nextfile>
                <nextid>2</nextid>
            </item>

            <item value="2" score="20">
                <content>
                    もって後3年だな。
                </content>
                <nextid>3</nextid>
            </item>
        </select>

        <!-- 質問に回答が存在する場合に項目のid属性値を記述します。 -->
        <!-- 正解/不正解画面を表示するように -->
        <!-- initArgを設定していない場合はあまり意味はありません-->
        <!-- ただし、複数選択などでscoreの付け方に -->
        <!-- 工夫したい時などに利用出来ます -->
        <answer>2</answer>

        <!-- 次に表示すべき質問のファイル名と、質問番号 -->
        <!-- 省略すると前の質問の情報が使われます。 -->
        <!-- これらの代わりにnexturl要素が記述されていた場合は -->
        <!-- 無条件にそこが開かれます。 -->
        <nextfile>question1.xml</nextfile>
        <nextid>3</nextid>
    </question>

    <question id="2">
        <content>
            Windowsが多くの人に使われている理由として
            考えられるものを答えてください。
        </content>

        <!-- 複数選択形式の場合に使います。いわゆるチェックボックス -->
        <multiselect shuffle="true">
            <item value="1" score="27">
                <!-- <item>配下に<nextid>等が無く、そのまま表示されても -->
                <!-- 良い場合は、<content>要素を省略して直接本文を書いても -->
                <!-- 構いません。 -->
                他の会社のものをつかわせないような細工をしているから
            </item>

            <item value="2" score="-6">
                優れたGUIの操作性
            </item>

            <item value="3" score="8">
                簡単にセキュリティを破れるので、クラッカーが
                Windowsをつかわせようと努力しているから
            </item>

            <item value="4" score="-20">
                使わないと時代に取り残されるから
            </item>

            <item value="5" score="20">
                他の人が乗り換えてくれないので、
                使わないとデータのやりとりができないから
            </item>
        </multiselect>

        <!-- 複数選択の回答は項目のidを出現順に','で区切って並べます。 -->
        <answer score="20">
            1,5
            <!-- 解答にマッチする回答だった場合のジャンプ先を指定する -->
            <!-- 場合は、ここにnextfile/nextidを記述します。 -->
            <nextfile>question1.xml</nextfile>
            <nextid>4</nextid>
        </answer>

        <nextid>3</nextid>
    </question>

    <question id="3">
        <content>
            Windowsに代わって世界を席巻するOSは何でしょう?
        </content>

        <select shuffle="true">
            <item value="1" score="1">
                Linux
            </item>
            <item value="2" score="2">
                FreeBSD
            </item>
            <item value="3" score="-2">
                OS-2
            </item>
            <item value="4" score="21">
                Macintosh
            </item>
            <item value="5" score="30">
                そんなものはない
            </item>
        </select>

        <!-- nexturlにはWebサーバが参照出来るURLを記述する必要があります。 -->
        <!-- 別のホストにしてしまうとSessionオブジェクトが参照出来ない -->
        <!-- のであまり意味がなくなります -->
        <nexturl>
            /~shin/jsp/question1.jsp
        </nexturl>
    </question>

    <question id="4">
        <content>
            (よくぞこんなところへ・・・)
            <em>それでもやっぱりビル・ゲイツはすごい</em>
        </content>

        <select>
            <item value="1" score="40">
                Yes
            </item>
            <item value="2" score="1">
                No
            </item>
        </select>

        <nexturl>
            /~shin/jsp/question1.jsp
        </nexturl>
    </question>
</questions>

このファイルを元にQuestion Servletを起動するには、
http://host/servlets/question?file=question1.xml
のように指定します。(↑実行例はこちら)

注:現在のバージョン1.0βではscore/遷移に正しく対応していません。
やけに長く見えますが、ツールを使って書くようになれば、XMLタグ部分を入力する必要はなくなるはずなので、作成は簡単です。
エディッタで行ったとしても、定型なので難しくはないと思います。

ちなみに、上記xmlソース中で指定されているquestion1.jspはこんな感じです。

<%@ page contentType="text/html; charset=ISO-2022-JP" %>
<html>
<head>
    <meta http-equiv="Content-Style-Type" content="text/css" />
    <link rel="stylesheet" href="../shin.css" type="text/css" />
    <title>サンプルの結果画面</title>
</head>
<body>
<h1>サンプルの結果</h1>
<%
    int score = ((Integer)session.getValue("score")).intValue();
%>
<h2>あなたの点数は<%= score %>です...</h2>
って、どういう基準だ?<br>
<br>
<br>

<%
    String[] s = session.getValueNames();
    if(s != null) {
%>
<h2>あなたの回答(と参考までにその他の情報も)の一覧</h2>
<table border="1">
<tr>
    <th>Parameter:</th>
    <th>Value:</th>
</tr>
<%
        for (int i = 0; i < s.length; i++) {
%>
<tr>
    <td><%= s[i] %></td>
    <td><%= session.getValue(s[i]) %></td>
</tr>
<%
        }
%>
</table>
<%
    }
%>
</body>
</html>
JSPを使うと上記のようにJavaプログラムをHTML文中に埋めこむことができます。
ServletやCGIでは、固定部分についてもprint文で出力しなければならなかったので、かなり楽になります。

5.表示されるスタイルの切り替え

3.に記した通り、initArgの[stylesheeturl]パラメタに指定したURL上のスタイルシートが利用されます。GETのパラメタに[stylesheeturl]を指定することでそのセッションのみの指定も可能です。
XMLから読み込まれた質問文は、デフォルトのtemplateではそれぞれ以下のようなclass属性が付けられて出力されます。

introduction <グループ>要素がある時の<導入文>
question 質問の本文
answercolumn 選択肢

また、以下のHTMLタグが使用されます。

h1 ページのタイトルの表示に使用されます。
h2 質問の題名に使用されます。
その他 <本文>要素内に記述されたHTML要素はそのまま使われることになります。

これらのclass/タグに対してスタイルを定義することも可能ですし、templateを書き替えることで、全く異なるフォーマットにすることもできます。

6.回答の集計について

最終結果を表示する画面は、ユーザの入力によって遷移先を変えるような場合は、単なるHTMLでもよいでしょう。その場合はpropertiesのpathで示されたパス上にファイルを配置できます。
ユーザの設定値に応じてスコアを集計したり、結果を求めるための処理が必要な場合は、遷移先としてServletかJSPのURLを指定することになります。
これらの中では、javax.servlet.http.HttpSessionオブジェクトにユーザの選択内容などが格納されていますので、これを解析して出力を行うようにします。
現状でHttpSessionに格納されているエントリは以下のような形式となっています。

[ファイル名]_[質問No] = 回答項目ID その<questions>の格納されたファイル名_その<question>のIDというキーに対して、選択された<項目>のIDが値となります。
複数選択の場合は、選択された項目のIDが','区切りでつなげられて格納されます。
例:
question1.xml_1=2
question1.xml_2=2,5

特殊なものとして、値が以下のものの場合は、下記の[_text]パラメタに実際の値が入ります。
Question.PARAMVALUE_ANSWERINPUT = "_answerinput" ::: 直接入力テキスト
Question.PARAMVALUE_ANSWERTIME = "_answertime" ::: 日付指定
[ファイル名]_[質問No]_text = テキスト 直接入力テキスト、及び、選択肢の「その他」が選ばれた場合の入力欄の内容が格納されます。
日付指定の場合については現状は"yyyy年mm月dd日 hh:mm:ss"形式の文字列が格納されます。
score = 点数 キー"score"には、xml中で選択項目毎等に付けられた「重み」の総和が格納されます。
使い方はいろいろあると思います。

7.質問のグループ化

4.に示したサンプルでは、一つの質問毎に送信を行うような形式であるため、遅い環境やダイヤルアップのクライアント環境などを考えると使い辛いので、質問のグループ化を行うサンプルを以下に示します。

XMLの方は省略します(非公開ディレクトリにあるので(汗))が、要は各<question>要素を<グループ>要素の内部に記述するというだけです。

途中までしか入力していません。全て解答したところで大した画面は出てきませんのでご注意!!!
新入社員向けに使おうかと思っている情報処理ニ種問題集
新入社員向けに使おうかと思っている情報処理ニ種問題集(スタイルを変えたバージョン)

8.回答の集計Servlet

アンケートの集計用ServletであるDataEntry/Extractについて記します。

以降は、まだメモレベルです。ちゃんとした説明になっていない部分があります。

質問集XMLファイル中の<nexturl>タグ中に、com.sk_jp.servlet.question.DataEntryというServletを表すURLを記述すると、そこまでの入力結果をファイルに蓄積します。
このときのファイル名は<質問集XMLファイル名>__Statistics.xmlとなります。従って、質問集毎に蓄積が行われます。

com.sk_jp.servlet.question.ExtractというServletに対して、fileパラメタにて質問集XMLファイル名を与えると、蓄積した結果の統計情報を表示するための絞り込み画面が表示されます。

サンプル「Servlet利用状況アンケート」

この集計機能に対してカスタマイズを行うために質問集xmlファイルに指定可能な属性があります。
属性はquestionタグに対して指定します。(質問毎に指定)

key その質問はキー項目となり、集計結果/絞り込み画面ともに表示されません。
キーである質問の回答について、蓄積した結果の中に同一の物があれば登録前に削除されます。
これはまだ仕様的によくないのですが、取り合えず、入力した人を特定する文字列を記入してもらうことで、以前の回答を更新出来るようにしています。
noextract その質問を抽出条件入力画面に表示しません。
invisible その質問を抽出結果画面に表示しません。