MDL-7974 Weekend Days Settings Chooses Wrong Day after Saving
[moodle.git] / question / format / xml / format.php
CommitLineData
84769fd8 1<?php // $Id$
2//
3///////////////////////////////////////////////////////////////
4// XML import/export
5//
6//////////////////////////////////////////////////////////////////////////
7// Based on default.php, included by ../import.php
8
84769fd8 9require_once( "$CFG->libdir/xmlize.php" );
10
f5565b69 11class qformat_xml extends qformat_default {
84769fd8 12
13 function provide_import() {
14 return true;
15 }
16
17 function provide_export() {
18 return true;
19 }
20
21 // IMPORT FUNCTIONS START HERE
22
6e557c08 23 /**
c81415c7 24 * Translate human readable format name
25 * into internal Moodle code number
6e557c08 26 * @param string name format name from xml file
27 * @return int Moodle format code
c81415c7 28 */
84769fd8 29 function trans_format( $name ) {
84769fd8 30 $name = trim($name);
31
32 if ($name=='moodle_auto_format') {
33 $id = 0;
34 }
35 elseif ($name=='html') {
36 $id = 1;
37 }
38 elseif ($name=='plain_text') {
39 $id = 2;
40 }
41 elseif ($name=='wiki_like') {
42 $id = 3;
43 }
44 elseif ($name=='markdown') {
45 $id = 4;
46 }
47 else {
48 $id = 0; // or maybe warning required
49 }
50 return $id;
51 }
52
6e557c08 53 /**
c81415c7 54 * Translate human readable single answer option
55 * to internal code number
6e557c08 56 * @param string name true/false
57 * @return int internal code number
c81415c7 58 */
84769fd8 59 function trans_single( $name ) {
2da44816 60 $name = trim($name);
61 if ($name == "false" || !$name) {
62 return 0;
63 } else {
64 return 1;
65 }
84769fd8 66 }
67
6e557c08 68 /**
c81415c7 69 * process text string from xml file
6e557c08 70 * @param array $text bit of xml tree after ['text']
71 * @return string processed text
c81415c7 72 */
84769fd8 73 function import_text( $text ) {
84769fd8 74 $data = $text[0]['#'];
75 $data = html_entity_decode( $data );
76 return addslashes(trim( $data ));
77 }
78
307f045f 79 /**
80 * Process text from an element in the XML that may or not be there.
81 * @param string $subelement the name of the element which is either present or missing.
82 * @param array $question a bit of xml tree, this method looks for $question['#'][$subelement][0]['#']['text'].
83 * @return string If $subelement is present, return the content of the text tag inside it.
84 * Otherwise returns an empty string.
85 */
86 function import_optional_text($subelement, $question) {
87 if (array_key_exists($subelement, $question['#'])) {
88 return $this->import_text($question['#'][$subelement][0]['#']['text']);
89 } else {
90 return '';
91 }
92 }
93
6e557c08 94 /**
c81415c7 95 * import parts of question common to all types
6e557c08 96 * @param array question question array from xml tree
97 * @return object question object
c81415c7 98 */
84769fd8 99 function import_headers( $question ) {
84769fd8 100 // this routine initialises the question object
101 $name = $this->import_text( $question['#']['name'][0]['#']['text'] );
102 $qtext = $this->import_text( $question['#']['questiontext'][0]['#']['text'] );
103 $qformat = $question['#']['questiontext'][0]['@']['format'];
104 $image = $question['#']['image'][0]['#'];
d08e16b2 105 if (!empty($question['#']['image_base64'][0]['#'])) {
106 $image_base64 = stripslashes( trim( $question['#']['image_base64'][0]['#'] ) );
107 $image = $this->importimagefile( $image, $image_base64 );
108 }
a4514d91 109 if (array_key_exists('generalfeedback', $question['#'])) {
110 $generalfeedback = $this->import_text( $question['#']['generalfeedback'][0]['#']['text'] );
1b8a7434 111 } else {
a4514d91 112 $generalfeedback = '';
1b8a7434 113 }
c81415c7 114 if (!empty($question['#']['defaultgrade'][0]['#'])) {
115 $qo->defaultgrade = $question['#']['defaultgrade'][0]['#'];
116 }
84769fd8 117 $penalty = $question['#']['penalty'][0]['#'];
118
51bcdf28 119 $qo = $this->defaultquestion();
84769fd8 120 $qo->name = $name;
121 $qo->questiontext = $qtext;
122 $qo->questiontextformat = $this->trans_format( $qformat );
123 $qo->image = ((!empty($image)) ? $image : '');
a4514d91 124 $qo->generalfeedback = $generalfeedback;
84769fd8 125 $qo->penalty = $penalty;
126
127 return $qo;
128 }
129
6e557c08 130 /**
c81415c7 131 * import the common parts of a single answer
6e557c08 132 * @param array answer xml tree for single answer
133 * @return object answer object
c81415c7 134 */
84769fd8 135 function import_answer( $answer ) {
84769fd8 136 $fraction = $answer['@']['fraction'];
137 $text = $this->import_text( $answer['#']['text']);
138 $feedback = $this->import_text( $answer['#']['feedback'][0]['#']['text'] );
139
140 $ans = null;
141 $ans->answer = $text;
142 $ans->fraction = $fraction / 100;
143 $ans->feedback = $feedback;
144
145 return $ans;
146 }
147
6e557c08 148 /**
c81415c7 149 * import multiple choice question
6e557c08 150 * @param array question question array from xml tree
151 * @return object question object
c81415c7 152 */
84769fd8 153 function import_multichoice( $question ) {
84769fd8 154 // get common parts
155 $qo = $this->import_headers( $question );
156
157 // 'header' parts particular to multichoice
158 $qo->qtype = MULTICHOICE;
159 $single = $question['#']['single'][0]['#'];
160 $qo->single = $this->trans_single( $single );
307f045f 161 if (array_key_exists('shuffleanswers', $question['#'])) {
162 $shuffleanswers = $question['#']['shuffleanswers'][0]['#'];
163 } else {
164 $shuffleanswers = 'false';
165 }
2da44816 166 $qo->shuffleanswers = $this->trans_single($shuffleanswers);
307f045f 167 $qo->correctfeedback = $this->import_optional_text('correctfeedback', $question);
168 $qo->partiallycorrectfeedback = $this->import_optional_text('partiallycorrectfeedback', $question);
169 $qo->incorrectfeedback = $this->import_optional_text('incorrectfeedback', $question);
170
84769fd8 171 // run through the answers
172 $answers = $question['#']['answer'];
173 $a_count = 0;
174 foreach ($answers as $answer) {
175 $ans = $this->import_answer( $answer );
176 $qo->answer[$a_count] = $ans->answer;
177 $qo->fraction[$a_count] = $ans->fraction;
178 $qo->feedback[$a_count] = $ans->feedback;
179 ++$a_count;
180 }
181
182 return $qo;
183 }
184
6e557c08 185 /**
c81415c7 186 * import cloze type question
6e557c08 187 * @param array question question array from xml tree
188 * @return object question object
c81415c7 189 */
7b8bc256 190 function import_multianswer( $questions ) {
7b8bc256 191 $qo = qtype_multianswer_extract_question($this->import_text(
192 $questions['#']['questiontext'][0]['#']['text'] ));
193
194 // 'header' parts particular to multianswer
195 $qo->qtype = MULTIANSWER;
196 $qo->course = $this->course;
197
71ffbac2 198 if (!empty($questions)) {
7b8bc256 199 $qo->name = $this->import_text( $questions['#']['name'][0]['#']['text'] );
200 }
201
202 return $qo;
203 }
204
6e557c08 205 /**
c81415c7 206 * import true/false type question
6e557c08 207 * @param array question question array from xml tree
208 * @return object question object
c81415c7 209 */
84769fd8 210 function import_truefalse( $question ) {
84769fd8 211 // get common parts
212 $qo = $this->import_headers( $question );
213
214 // 'header' parts particular to true/false
215 $qo->qtype = TRUEFALSE;
216
217 // get answer info
218 $answers = $question['#']['answer'];
219 $fraction0 = $answers[0]['@']['fraction'];
220 $feedback0 = $this->import_text($answers[0]['#']['feedback'][0]['#']['text']);
221 $fraction1 = $answers[1]['@']['fraction'];
222 $feedback1 = $this->import_text($answers[1]['#']['feedback'][0]['#']['text']);
223
224 // sort out which is true and build object accordingly
225 if ($fraction0==100) { // then 0 index is true
226 $qo->answer = 1;
227 $qo->feedbacktrue=$feedback0;
228 $qo->feedbackfalse=$feedback1;
229 }
230 else {
231 $qo->answer = 0;
232 $qo->feedbacktrue = $feedback1;
233 $qo->feedbackfalse = $feedback0;
234 }
235
236 return $qo;
237 }
238
6e557c08 239 /**
c81415c7 240 * import short answer type question
6e557c08 241 * @param array question question array from xml tree
242 * @return object question object
c81415c7 243 */
84769fd8 244 function import_shortanswer( $question ) {
84769fd8 245 // get common parts
246 $qo = $this->import_headers( $question );
247
248 // header parts particular to shortanswer
249 $qo->qtype = SHORTANSWER;
250
251 // get usecase
252 $qo->usecase = $question['#']['usecase'][0]['#'];
253
254 // run through the answers
255 $answers = $question['#']['answer'];
256 $a_count = 0;
257 foreach ($answers as $answer) {
258 $ans = $this->import_answer( $answer );
259 $qo->answer[$a_count] = $ans->answer;
260 $qo->fraction[$a_count] = $ans->fraction;
261 $qo->feedback[$a_count] = $ans->feedback;
262 ++$a_count;
263 }
264
265 return $qo;
266 }
7b8bc256 267
6e557c08 268 /**
c81415c7 269 * import regexp type question
6e557c08 270 * @param array question question array from xml tree
271 * @return object question object
c81415c7 272 */
7b8bc256 273 function import_regexp( $question ) {
7b8bc256 274 // get common parts
275 $qo = $this->import_headers( $question );
276
277 // header parts particular to shortanswer
278 $qo->qtype = regexp;
279
280 // get usecase
281 $qo->usecase = $question['#']['usecase'][0]['#'];
282
283 // run through the answers
284 $answers = $question['#']['answer'];
285 $a_count = 0;
286 foreach ($answers as $answer) {
287 $ans = $this->import_answer( $answer );
288 $qo->answer[$a_count] = $ans->answer;
289 $qo->fraction[$a_count] = $ans->fraction;
290 $qo->feedback[$a_count] = $ans->feedback;
291 ++$a_count;
292 }
84769fd8 293
7b8bc256 294 return $qo;
295 }
296
6e557c08 297 /**
c81415c7 298 * import description type question
6e557c08 299 * @param array question question array from xml tree
300 * @return object question object
c81415c7 301 */
7b8bc256 302 function import_description( $question ) {
303 // get common parts
304 $qo = $this->import_headers( $question );
305 // header parts particular to shortanswer
306 $qo->qtype = DESCRIPTION;
307 return $qo;
308 }
84769fd8 309
6e557c08 310 /**
c81415c7 311 * import numerical type question
6e557c08 312 * @param array question question array from xml tree
313 * @return object question object
c81415c7 314 */
315 function import_numerical( $question ) {
84769fd8 316 // get common parts
317 $qo = $this->import_headers( $question );
318
319 // header parts particular to numerical
320 $qo->qtype = NUMERICAL;
321
322 // get answers array
323 $answers = $question['#']['answer'];
324 $qo->answer = array();
325 $qo->feedback = array();
326 $qo->fraction = array();
327 $qo->tolerance = array();
328 foreach ($answers as $answer) {
55894a42 329 $answertext = trim($answer['#'][0]);
330 if ($answertext == '') {
331 $qo->answer[] = '*';
332 } else {
333 $qo->answer[] = $answertext;
334 }
a0d187bf 335 $qo->feedback[] = $this->import_text( $answer['#']['feedback'][0]['#']['text'] );
84769fd8 336 $qo->fraction[] = $answer['#']['fraction'][0]['#'];
337 $qo->tolerance[] = $answer['#']['tolerance'][0]['#'];
338 }
339
340 // get units array
84769fd8 341 $qo->unit = array();
a0d187bf 342 if (isset($question['#']['units'][0]['#']['unit'])) {
343 $units = $question['#']['units'][0]['#']['unit'];
344 $qo->multiplier = array();
345 foreach ($units as $unit) {
346 $qo->multiplier[] = $unit['#']['multiplier'][0]['#'];
347 $qo->unit[] = $unit['#']['unit_name'][0]['#'];
348 }
84769fd8 349 }
84769fd8 350 return $qo;
351 }
352
6e557c08 353 /**
c81415c7 354 * import matching type question
6e557c08 355 * @param array question question array from xml tree
356 * @return object question object
c81415c7 357 */
51bcdf28 358 function import_matching( $question ) {
51bcdf28 359 // get common parts
360 $qo = $this->import_headers( $question );
361
362 // header parts particular to matching
363 $qo->qtype = MATCH;
ee800653 364 if (!empty($question['#']['shuffleanswers'])) {
365 $qo->shuffleanswers = $question['#']['shuffleanswers'][0]['#'];
366 } else {
367 $qo->shuffleanswers = false;
368 }
51bcdf28 369
370 // get subquestions
371 $subquestions = $question['#']['subquestion'];
372 $qo->subquestions = array();
373 $qo->subanswers = array();
374
375 // run through subquestions
376 foreach ($subquestions as $subquestion) {
a0d187bf 377 $qtext = $this->import_text( $subquestion['#']['text'] );
378 $atext = $this->import_text( $subquestion['#']['answer'][0]['#']['text'] );
51bcdf28 379 $qo->subquestions[] = $qtext;
380 $qo->subanswers[] = $atext;
381 }
51bcdf28 382 return $qo;
383 }
384
6e557c08 385 /**
c81415c7 386 * import essay type question
6e557c08 387 * @param array question question array from xml tree
388 * @return object question object
c81415c7 389 */
390 function import_essay( $question ) {
391 // get common parts
392 $qo = $this->import_headers( $question );
393
394 // header parts particular to essay
395 $qo->qtype = ESSAY;
396
397 // get feedback
398 $qo->feedback = $this->import_text( $question['#']['answer'][0]['#']['feedback'][0]['#']['text'] );
399
400 // get fraction
401 $qo->fraction = $question['#']['answer'][0]['#']['fraction'][0]['#'];
402
403 return $qo;
404 }
84769fd8 405
ee259d0c 406 /**
407 * this is not a real question type. It's a dummy type used
408 * to specify the import category
409 * format is:
410 * <question type="category">
411 * <category>tom/dick/harry</category>
412 * </question>
413 */
414 function import_category( $question ) {
415 $qo->qtype = 'category';
416 $qo->category = $question['#']['category'][0]['#'];
417 return $qo;
418 }
419
c81415c7 420 /**
421 * parse the array of lines into an array of questions
422 * this *could* burn memory - but it won't happen that much
423 * so fingers crossed!
6e557c08 424 * @param array lines array of lines from the input file
425 * @return array (of objects) question objects
c81415c7 426 */
427 function readquestions($lines) {
84769fd8 428 // we just need it as one big string
429 $text = implode($lines, " ");
430 unset( $lines );
431
432 // this converts xml to big nasty data structure
433 // the 0 means keep white space as it is (important for markdown format)
434 // print_r it if you want to see what it looks like!
435 $xml = xmlize( $text, 0 );
436
437 // set up array to hold all our questions
438 $questions = array();
439
440 // iterate through questions
441 foreach ($xml['quiz']['#']['question'] as $question) {
442 $question_type = $question['@']['type'];
443 $questiontype = get_string( 'questiontype','quiz',$question_type );
84769fd8 444
445 if ($question_type=='multichoice') {
446 $qo = $this->import_multichoice( $question );
447 }
448 elseif ($question_type=='truefalse') {
449 $qo = $this->import_truefalse( $question );
450 }
451 elseif ($question_type=='shortanswer') {
452 $qo = $this->import_shortanswer( $question );
453 }
7b8bc256 454 //elseif ($question_type=='regexp') {
455 // $qo = $this->import_regexp( $question );
456 //}
84769fd8 457 elseif ($question_type=='numerical') {
458 $qo = $this->import_numerical( $question );
459 }
7b8bc256 460 elseif ($question_type=='description') {
461 $qo = $this->import_description( $question );
462 }
51bcdf28 463 elseif ($question_type=='matching') {
464 $qo = $this->import_matching( $question );
465 }
7b8bc256 466 elseif ($question_type=='cloze') {
c81415c7 467 $qo = $this->import_multianswer( $question );
468 }
469 elseif ($question_type=='essay') {
470 $qo = $this->import_essay( $question );
7b8bc256 471 }
ee259d0c 472 elseif ($question_type=='category') {
473 $qo = $this->import_category( $question );
474 }
84769fd8 475 else {
ee800653 476 $notsupported = get_string( 'xmltypeunsupported','quiz',$question_type );
84769fd8 477 echo "<p>$notsupported</p>";
478 $qo = null;
479 }
480
481 // stick the result in the $questions array
482 if ($qo) {
483 $questions[] = $qo;
484 }
485 }
84769fd8 486 return $questions;
487 }
488
489 // EXPORT FUNCTIONS START HERE
490
84769fd8 491 function export_file_extension() {
492 // override default type so extension is .xml
493
494 return ".xml";
495 }
496
c81415c7 497
498 /**
499 * Turn the internal question code into a human readable form
500 * (The code used to be numeric, but this remains as some of
501 * the names don't match the new internal format)
6e557c08 502 * @param mixed type_id Internal code
503 * @return string question type string
c81415c7 504 */
84769fd8 505 function get_qtype( $type_id ) {
84769fd8 506 switch( $type_id ) {
507 case TRUEFALSE:
508 $name = 'truefalse';
509 break;
510 case MULTICHOICE:
511 $name = 'multichoice';
512 break;
513 case SHORTANSWER:
514 $name = 'shortanswer';
515 break;
7b8bc256 516 //case regexp:
517 // $name = 'regexp';
518 // break;
84769fd8 519 case NUMERICAL:
520 $name = 'numerical';
521 break;
522 case MATCH:
523 $name = 'matching';
524 break;
525 case DESCRIPTION:
526 $name = 'description';
527 break;
528 case MULTIANSWER:
529 $name = 'cloze';
530 break;
c81415c7 531 case ESSAY:
532 $name = 'essay';
533 break;
84769fd8 534 default:
535 $name = 'unknown';
536 }
537 return $name;
538 }
539
6e557c08 540 /**
c81415c7 541 * Convert internal Moodle text format code into
542 * human readable form
6e557c08 543 * @param int id internal code
544 * @return string format text
c81415c7 545 */
84769fd8 546 function get_format( $id ) {
84769fd8 547 switch( $id ) {
548 case 0:
549 $name = "moodle_auto_format";
550 break;
551 case 1:
552 $name = "html";
553 break;
554 case 2:
555 $name = "plain_text";
556 break;
557 case 3:
558 $name = "wiki_like";
559 break;
560 case 4:
561 $name = "markdown";
562 break;
563 default:
564 $name = "unknown";
565 }
566 return $name;
567 }
568
6e557c08 569 /**
c81415c7 570 * Convert internal single question code into
571 * human readable form
6e557c08 572 * @param int id single question code
573 * @return string single question string
c81415c7 574 */
84769fd8 575 function get_single( $id ) {
84769fd8 576 switch( $id ) {
577 case 0:
578 $name = "false";
579 break;
580 case 1:
581 $name = "true";
582 break;
583 default:
584 $name = "unknown";
585 }
586 return $name;
587 }
588
6e557c08 589 /**
c81415c7 590 * generates <text></text> tags, processing raw text therein
6e557c08 591 * @param int ilev the current indent level
592 * @param boolean short stick it on one line
593 * @return string formatted text
c81415c7 594 */
84769fd8 595 function writetext( $raw, $ilev=0, $short=true) {
84769fd8 596 $indent = str_repeat( " ",$ilev );
597
598 // encode the text to 'disguise' HTML content
599 $raw = htmlspecialchars( $raw );
600
601 if ($short) {
602 $xml = "$indent<text>$raw</text>\n";
603 }
604 else {
605 $xml = "$indent<text>\n$raw\n$indent</text>\n";
606 }
607
608 return $xml;
609 }
610
611 function presave_process( $content ) {
612 // override method to allow us to add xml headers and footers
613
614 $content = "<?xml version=\"1.0\"?>\n" .
615 "<quiz>\n" .
616 $content . "\n" .
617 "</quiz>";
618
619 return $content;
620 }
621
6e557c08 622 /**
c81415c7 623 * Include an image encoded in base 64
6e557c08 624 * @param string imagepath The location of the image file
625 * @return string xml code segment
c81415c7 626 */
d08e16b2 627 function writeimage( $imagepath ) {
d08e16b2 628 global $CFG;
629
630 if (empty($imagepath)) {
631 return '';
632 }
633
634 $courseid = $this->course->id;
635 if (!$binary = file_get_contents( "{$CFG->dataroot}/$courseid/$imagepath" )) {
636 return '';
637 }
638
639 $content = " <image_base64>\n".addslashes(base64_encode( $binary ))."\n".
640 "\n </image_base64>\n";
641 return $content;
642 }
643
6e557c08 644 /**
c81415c7 645 * Turns question into an xml segment
6e557c08 646 * @param array question question array
647 * @return string xml segment
c81415c7 648 */
84769fd8 649 function writequestion( $question ) {
84769fd8 650 // initial string;
651 $expout = "";
652
653 // add comment
654 $expout .= "\n\n<!-- question: $question->id -->\n";
655
656 // add opening tag
7b8bc256 657 // generates specific header for Cloze type question
658 if ($question->qtype != MULTIANSWER) {
659 // for all question types except Close
660 $question_type = $this->get_qtype( $question->qtype );
661 $name_text = $this->writetext( $question->name );
662 $qtformat = $this->get_format($question->questiontextformat);
663 $question_text = $this->writetext( $question->questiontext );
a4514d91 664 $generalfeedback = $this->writetext( $question->generalfeedback );
7b8bc256 665 $expout .= " <question type=\"$question_type\">\n";
666 $expout .= " <name>$name_text</name>\n";
667 $expout .= " <questiontext format=\"$qtformat\">\n";
668 $expout .= $question_text;
669 $expout .= " </questiontext>\n";
670 $expout .= " <image>{$question->image}</image>\n";
671 $expout .= $this->writeimage($question->image);
a4514d91 672 $expout .= " <generalfeedback>\n";
673 $expout .= $generalfeedback;
674 $expout .= " </generalfeedback>\n";
c81415c7 675 $expout .= " <defaultgrade>{$question->defaultgrade}</defaultgrade>\n";
7b8bc256 676 $expout .= " <penalty>{$question->penalty}</penalty>\n";
677 $expout .= " <hidden>{$question->hidden}</hidden>\n";
678 }
679 else {
680 // for Cloze type only
681 $question_type = $this->get_qtype( $question->qtype );
682 $name_text = $this->writetext( $question->name );
683 $question_text = $this->writetext( $question->questiontext );
684 $expout .= " <question type=\"$question_type\">\n";
685 $expout .= " <name>$name_text</name>\n";
686 $expout .= " <questiontext>\n";
687 $expout .= $question_text;
688 $expout .= " </questiontext>\n";
689 }
690
d08e16b2 691 if (!empty($question->options->shuffleanswers)) {
692 $expout .= " <shuffleanswers>{$question->options->shuffleanswers}</shuffleanswers>\n";
693 }
694 else {
695 $expout .= " <shuffleanswers>0</shuffleanswers>\n";
696 }
84769fd8 697
698 // output depends on question type
699 switch($question->qtype) {
700 case TRUEFALSE:
36e2232e 701 foreach ($question->options->answers as $answer) {
702 $fraction_pc = round( $answer->fraction * 100 );
703 $expout .= " <answer fraction=\"$fraction_pc\">\n";
704 $expout .= $this->writetext(strtolower($answer->answer),3)."\n";
705 $expout .= " <feedback>\n";
706 $expout .= $this->writetext( $answer->feedback,4,false );
707 $expout .= " </feedback>\n";
708 $expout .= " </answer>\n";
709 }
84769fd8 710 break;
711 case MULTICHOICE:
712 $expout .= " <single>".$this->get_single($question->options->single)."</single>\n";
307f045f 713 $expout .= " <shuffleanswers>".$this->get_single($question->options->shuffleanswers)."</shuffleanswers>\n";
714 $expout .= " <correctfeedback>".$this->writetext($question->options->correctfeedback, 3)."</correctfeedback>\n";
715 $expout .= " <partiallycorrectfeedback>".$this->writetext($question->options->partiallycorrectfeedback, 3)."</partiallycorrectfeedback>\n";
716 $expout .= " <incorrectfeedback>".$this->writetext($question->options->incorrectfeedback, 3)."</incorrectfeedback>\n";
84769fd8 717 foreach($question->options->answers as $answer) {
718 $percent = $answer->fraction * 100;
719 $expout .= " <answer fraction=\"$percent\">\n";
720 $expout .= $this->writetext( $answer->answer,4,false );
721 $expout .= " <feedback>\n";
6e557c08 722 $expout .= $this->writetext( $answer->feedback,5,false );
84769fd8 723 $expout .= " </feedback>\n";
724 $expout .= " </answer>\n";
725 }
726 break;
727 case SHORTANSWER:
728 $expout .= " <usecase>{$question->options->usecase}</usecase>\n ";
729 foreach($question->options->answers as $answer) {
730 $percent = 100 * $answer->fraction;
731 $expout .= " <answer fraction=\"$percent\">\n";
732 $expout .= $this->writetext( $answer->answer,3,false );
733 $expout .= " <feedback>\n";
734 $expout .= $this->writetext( $answer->feedback,4,false );
735 $expout .= " </feedback>\n";
736 $expout .= " </answer>\n";
737 }
738 break;
7b8bc256 739 //case regexp:
740 //$expout .= " <usecase>{$question->options->usecase}</usecase>\n ";
741 // foreach($question->options->answers as $answer) {
742 // $percent = 100 * $answer->fraction;
743 // $expout .= " <answer fraction=\"$percent\">\n";
744 // $expout .= $this->writetext( $answer->answer,3,false );
745 // $expout .= " <feedback>\n";
746 // $expout .= $this->writetext( $answer->feedback,4,false );
747 // $expout .= " </feedback>\n";
748 // $expout .= " </answer>\n";
749 // }
750 // break;
84769fd8 751 case NUMERICAL:
752 foreach ($question->options->answers as $answer) {
753 $tolerance = $answer->tolerance;
754 $expout .= "<answer>\n";
755 $expout .= " {$answer->answer}\n";
756 $expout .= " <tolerance>$tolerance</tolerance>\n";
757 $expout .= " <feedback>".$this->writetext( $answer->feedback )."</feedback>\n";
758 $expout .= " <fraction>{$answer->fraction}</fraction>\n";
759 $expout .= "</answer>\n";
760 }
761
762 $units = $question->options->units;
763 if (count($units)) {
764 $expout .= "<units>\n";
765 foreach ($units as $unit) {
766 $expout .= " <unit>\n";
767 $expout .= " <multiplier>{$unit->multiplier}</multiplier>\n";
768 $expout .= " <unit_name>{$unit->unit}</unit_name>\n";
769 $expout .= " </unit>\n";
770 }
771 $expout .= "</units>\n";
772 }
773 break;
774 case MATCH:
775 foreach($question->options->subquestions as $subquestion) {
776 $expout .= "<subquestion>\n";
777 $expout .= $this->writetext( $subquestion->questiontext );
778 $expout .= "<answer>".$this->writetext( $subquestion->answertext )."</answer>\n";
779 $expout .= "</subquestion>\n";
780 }
781 break;
782 case DESCRIPTION:
c81415c7 783 // nothing more to do for this type
84769fd8 784 break;
785 case MULTIANSWER:
7b8bc256 786 $a_count=1;
787 foreach($question->options->questions as $question) {
788 $thispattern = addslashes("{#".$a_count."}");
789 $thisreplace = $question->questiontext;
790 $expout=ereg_replace($thispattern, $thisreplace, $expout );
791 $a_count++;
792 }
793 break;
c81415c7 794 case ESSAY:
795 foreach ($question->options->answers as $answer) {
796 $expout .= "<answer>\n";
797 $expout .= " <feedback>".$this->writetext( $answer->feedback )."</feedback>\n";
798 $expout .= " <fraction>{$answer->fraction}</fraction>\n";
799 $expout .= "</answer>\n";
800 }
801
802 break;
84769fd8 803 default:
804 $expout .= "<!-- Question type is unknown or not supported (Type=$question->qtype) -->\n";
805 }
806
807 // close the question tag
808 $expout .= "</question>\n";
809
84769fd8 810 return $expout;
811 }
812}
813
814?>