3 ////////////////////////////////////////////////////////////////////////////
4 /// Blackboard 6.0 Format
6 /// This Moodle class provides all functions necessary to import and export
9 ////////////////////////////////////////////////////////////////////////////
11 // Based on default.php, included by ../import.php
13 * @package questionbank
14 * @subpackage importexport
16 require_once ("$CFG->libdir/xmlize.php");
17 require_once ("$CFG->libdir/tcpdf/html_entity_decode_php4.php");
19 class qformat_blackboard
extends qformat_default
{
21 function provide_import() {
26 /********************************
28 function readdata($filename) {
29 /// Returns complete file with an array, one item per line
31 if (is_readable($filename)) {
33 $zip = zip_open($filename);
34 $zip_entry = $zip_read($zip);
35 if (strstr($zip_entry_name($zip_entry), "imsmanifest") == 0)
36 $zip_entry = $zip_read($zip); // skip past manifest file
38 if (zip_entry_open($zip, $zip_entry, "r")) {
40 $strbuf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
41 $buf = explode("\n", $strbuf);
42 zip_entry_close($zip_entry);
58 ********************************/
60 function readquestions ($lines) {
61 /// Parses an array of lines into an array of questions,
62 /// where each item is a question object as defined by
65 $text = implode($lines, " ");
66 $xml = xmlize($text, 0);
70 $this->process_tf($xml, $questions);
71 $this->process_mc($xml, $questions);
72 $this->process_ma($xml, $questions);
73 $this->process_fib($xml, $questions);
74 $this->process_matching($xml, $questions);
79 //----------------------------------------
80 // Process True / False Questions
81 //----------------------------------------
82 function process_tf($xml, &$questions) {
84 if (isset($xml["POOL"]["#"]["QUESTION_TRUEFALSE"])) {
85 $tfquestions = $xml["POOL"]["#"]["QUESTION_TRUEFALSE"];
91 for ($i = 0; $i < sizeof ($tfquestions); $i++
) {
93 $question = $this->defaultquestion();
95 $question->qtype
= TRUEFALSE
;
96 $question->single
= 1; // Only one answer is allowed
98 $thisquestion = $tfquestions[$i];
100 // determine if the question is already escaped html
101 $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
103 // put questiontext in question object
105 $question->questiontext
= html_entity_decode_php4(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
107 $question->questiontext
= addslashes($question->questiontext
);
108 // put name in question object
109 $question->name
= substr($question->questiontext
, 0, 254);
111 $choices = $thisquestion["#"]["ANSWER"];
113 $correct_answer = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"][0]["@"]["answer_id"];
115 // first choice is true, second is false.
116 $id = $choices[0]["@"]["id"];
118 if (strcmp($id, $correct_answer) == 0) { // true is correct
119 $question->answer
= 1;
120 $question->feedbacktrue
= addslashes(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
121 $question->feedbackfalse
= addslashes(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
122 } else { // false is correct
123 $question->answer
= 0;
124 $question->feedbacktrue
= addslashes(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
125 $question->feedbackfalse
= addslashes(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
127 $question->correctanswer
= $question->answer
;
128 $questions[] = $question;
132 //----------------------------------------
133 // Process Multiple Choice Questions
134 //----------------------------------------
135 function process_mc($xml, &$questions) {
137 if (isset($xml["POOL"]["#"]["QUESTION_MULTIPLECHOICE"])) {
138 $mcquestions = $xml["POOL"]["#"]["QUESTION_MULTIPLECHOICE"];
144 for ($i = 0; $i < sizeof ($mcquestions); $i++
) {
146 $question = $this->defaultquestion();
148 $question->qtype
= MULTICHOICE
;
149 $question->single
= 1; // Only one answer is allowed
151 $thisquestion = $mcquestions[$i];
153 // determine if the question is already escaped html
154 $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
156 // put questiontext in question object
158 $question->questiontext
= html_entity_decode_php4(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
160 $question->questiontext
= addslashes($question->questiontext
);
162 // put name of question in question object, careful of length
163 $question->name
= substr($question->questiontext
, 0, 254);
165 $choices = $thisquestion["#"]["ANSWER"];
166 for ($j = 0; $j < sizeof ($choices); $j++
) {
168 $choice = trim($choices[$j]["#"]["TEXT"][0]["#"]);
169 // put this choice in the question object.
171 $question->answer
[$j] = html_entity_decode_php4($choice);
173 $question->answer
[$j] = addslashes($question->answer
[$j]);
175 $id = $choices[$j]["@"]["id"];
176 $correct_answer_id = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"][0]["@"]["answer_id"];
177 // if choice is the answer, give 100%, otherwise give 0%
178 if (strcmp ($id, $correct_answer_id) == 0) {
179 $question->fraction
[$j] = 1;
181 $question->feedback
[$j] = html_entity_decode_php4(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
183 $question->feedback
[$j] = addslashes($question->feedback
[$j]);
185 $question->fraction
[$j] = 0;
187 $question->feedback
[$j] = html_entity_decode_php4(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
189 $question->feedback
[$j] = addslashes($question->feedback
[$j]);
192 $questions[] = $question;
196 //----------------------------------------
197 // Process Multiple Choice Questions With Multiple Answers
198 //----------------------------------------
199 function process_ma($xml, &$questions) {
201 if (isset($xml["POOL"]["#"]["QUESTION_MULTIPLEANSWER"])) {
202 $maquestions = $xml["POOL"]["#"]["QUESTION_MULTIPLEANSWER"];
208 for ($i = 0; $i < sizeof ($maquestions); $i++
) {
210 $question = $this->defaultquestion();
212 $question->qtype
= MULTICHOICE
;
213 $question->defaultgrade
= 1;
214 $question->single
= 0; // More than one answers allowed
215 $question->image
= ""; // No images with this format
217 $thisquestion = $maquestions[$i];
219 // determine if the question is already escaped html
220 $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
222 // put questiontext in question object
224 $question->questiontext
= html_entity_decode_php4(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
226 $question->questiontext
= addslashes($question->questiontext
);
227 // put name of question in question object
228 $question->name
= substr($question->questiontext
, 0, 254);
230 $choices = $thisquestion["#"]["ANSWER"];
231 $correctanswers = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"];
233 for ($j = 0; $j < sizeof ($choices); $j++
) {
235 $choice = trim($choices[$j]["#"]["TEXT"][0]["#"]);
236 // put this choice in the question object.
237 $question->answer
[$j] = addslashes($choice);
239 $correctanswercount = sizeof($correctanswers);
240 $id = $choices[$j]["@"]["id"];
242 for ($k = 0; $k < $correctanswercount; $k++
) {
244 $correct_answer_id = trim($correctanswers[$k]["@"]["answer_id"]);
245 if (strcmp ($id, $correct_answer_id) == 0) {
251 $question->fraction
[$j] = floor(100000/$correctanswercount)/100000; // strange behavior if we have more than 5 decimal places
252 $question->feedback
[$j] = addslashes(trim($thisquestion["#"]["GRADABLE"][$j]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
254 $question->fraction
[$j] = 0;
255 $question->feedback
[$j] = addslashes(trim($thisquestion["#"]["GRADABLE"][$j]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
259 $questions[] = $question;
263 //----------------------------------------
264 // Process Fill in the Blank Questions
265 //----------------------------------------
266 function process_fib($xml, &$questions) {
268 if (isset($xml["POOL"]["#"]["QUESTION_FILLINBLANK"])) {
269 $fibquestions = $xml["POOL"]["#"]["QUESTION_FILLINBLANK"];
275 for ($i = 0; $i < sizeof ($fibquestions); $i++
) {
276 $question = $this->defaultquestion();
278 $question->qtype
= SHORTANSWER
;
279 $question->usecase
= 0; // Ignore case
281 $thisquestion = $fibquestions[$i];
283 // determine if the question is already escaped html
284 $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
286 // put questiontext in question object
288 $question->questiontext
= html_entity_decode_php4(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
290 $question->questiontext
= addslashes($question->questiontext
);
291 // put name of question in question object
292 $question->name
= substr($question->questiontext
, 0, 254);
294 $answer = trim($thisquestion["#"]["ANSWER"][0]["#"]["TEXT"][0]["#"]);
296 $question->answer
[] = addslashes($answer);
297 $question->fraction
[] = 1;
298 $question->feedback
= array();
300 if (is_array( $thisquestion['#']['GRADABLE'][0]['#'] )) {
301 $question->feedback
[0] = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
304 $question->feedback
[0] = '';
306 if (is_array( $thisquestion["#"]["GRADABLE"][0]["#"] )) {
307 $question->feedback
[1] = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
310 $question->feedback
[1] = '';
313 $questions[] = $question;
317 //----------------------------------------
318 // Process Matching Questions
319 //----------------------------------------
320 function process_matching($xml, &$questions) {
322 if (isset($xml["POOL"]["#"]["QUESTION_MATCH"])) {
323 $matchquestions = $xml["POOL"]["#"]["QUESTION_MATCH"];
329 for ($i = 0; $i < sizeof ($matchquestions); $i++
) {
331 $question = $this->defaultquestion();
333 $question->qtype
= MATCH
;
335 $thisquestion = $matchquestions[$i];
337 // determine if the question is already escaped html
338 $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
340 // put questiontext in question object
342 $question->questiontext
= html_entity_decode_php4(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
344 $question->questiontext
= addslashes($question->questiontext
);
345 // put name of question in question object
346 $question->name
= substr($question->questiontext
, 0, 254);
348 $choices = $thisquestion["#"]["CHOICE"];
349 for ($j = 0; $j < sizeof ($choices); $j++
) {
353 $choice = $choices[$j]["#"]["TEXT"][0]["#"];
354 $choice_id = $choices[$j]["@"]["id"];
356 $question->subanswers
[] = addslashes(trim($choice));
358 $correctanswers = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"];
359 for ($k = 0; $k < sizeof ($correctanswers); $k++
) {
361 if (strcmp($choice_id, $correctanswers[$k]["@"]["choice_id"]) == 0) {
363 $answer_id = $correctanswers[$k]["@"]["answer_id"];
365 $answers = $thisquestion["#"]["ANSWER"];
366 for ($m = 0; $m < sizeof ($answers); $m++
) {
368 $answer = $answers[$m];
369 $current_ans_id = $answer["@"]["id"];
370 if (strcmp ($current_ans_id, $answer_id) == 0) {
372 $answer = $answer["#"]["TEXT"][0]["#"];
373 $question->subquestions
[] = addslashes(trim($answer));
388 $questions[] = $question;