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