Merge commit 'catalyst/MOODLE_19_STABLE' into mdl19-linuxchix
[moodle-linuxchix.git] / question / format / blackboard / format.php
blobc8e1330cfe1477023cffbacb8dc617b2251b2843
1 <?php // $Id$
3 ////////////////////////////////////////////////////////////////////////////
4 /// Blackboard 6.0 Format
5 ///
6 /// This Moodle class provides all functions necessary to import and export
7 ///
8 ///
9 ////////////////////////////////////////////////////////////////////////////
11 // Based on default.php, included by ../import.php
12 /**
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() {
22 return true;
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);
43 zip_close($zip);
44 return $buf;
46 } else {
48 zip_close($zip);
49 return false;
55 return false;
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
63 /// readquestion().
65 $text = implode($lines, " ");
66 $xml = xmlize($text, 0);
68 $questions = array();
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);
76 return $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"];
87 else {
88 return;
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
104 if ($ishtml) {
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"];
140 else {
141 return;
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
157 if ($ishtml) {
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.
170 if ($ishtml) {
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;
180 if ($ishtml) {
181 $question->feedback[$j] = html_entity_decode_php4(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
183 $question->feedback[$j] = addslashes($question->feedback[$j]);
184 } else {
185 $question->fraction[$j] = 0;
186 if ($ishtml) {
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"];
204 else {
205 return;
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
223 if ($ishtml) {
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"];
241 $iscorrect = 0;
242 for ($k = 0; $k < $correctanswercount; $k++) {
244 $correct_answer_id = trim($correctanswers[$k]["@"]["answer_id"]);
245 if (strcmp ($id, $correct_answer_id) == 0) {
246 $iscorrect = 1;
250 if ($iscorrect) {
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]["#"]));
253 } else {
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"];
271 else {
272 return;
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
287 if ($ishtml) {
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]["#"]));
303 else {
304 $question->feedback[0] = '';
306 if (is_array( $thisquestion["#"]["GRADABLE"][0]["#"] )) {
307 $question->feedback[1] = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
309 else {
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"];
325 else {
326 return;
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
341 if ($ishtml) {
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++) {
351 $subquestion = NULL;
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));
374 break;
380 break;
388 $questions[] = $question;