ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
class.assClozeTestExport.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once "./Modules/TestQuestionPool/classes/export/qti12/class.assQuestionExport.php";
5
16{
26 function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
27 {
28 global $ilias;
29
30 include_once "./Services/Math/classes/class.EvalMath.php";
31 $eval = new EvalMath();
32 $eval->suppress_errors = TRUE;
33 include_once("./Services/Xml/classes/class.ilXmlWriter.php");
34 $a_xml_writer = new ilXmlWriter;
35 // set xml header
36 $a_xml_writer->xmlHeader();
37 $a_xml_writer->xmlStartTag("questestinterop");
38 $attrs = array(
39 "ident" => "il_".IL_INST_ID."_qst_".$this->object->getId(),
40 "title" => $this->object->getTitle(),
41 "maxattempts" => $this->object->getNrOfTries()
42 );
43 $a_xml_writer->xmlStartTag("item", $attrs);
44 // add question description
45 $a_xml_writer->xmlElement("qticomment", NULL, $this->object->getComment());
46 // add estimated working time
47 $workingtime = $this->object->getEstimatedWorkingTime();
48 $duration = sprintf("P0Y0M0DT%dH%dM%dS", $workingtime["h"], $workingtime["m"], $workingtime["s"]);
49 $a_xml_writer->xmlElement("duration", NULL, $duration);
50 // add ILIAS specific metadata
51 $a_xml_writer->xmlStartTag("itemmetadata");
52 $a_xml_writer->xmlStartTag("qtimetadata");
53 $a_xml_writer->xmlStartTag("qtimetadatafield");
54 $a_xml_writer->xmlElement("fieldlabel", NULL, "ILIAS_VERSION");
55 $a_xml_writer->xmlElement("fieldentry", NULL, $ilias->getSetting("ilias_version"));
56 $a_xml_writer->xmlEndTag("qtimetadatafield");
57 $a_xml_writer->xmlStartTag("qtimetadatafield");
58 $a_xml_writer->xmlElement("fieldlabel", NULL, "QUESTIONTYPE");
59 $a_xml_writer->xmlElement("fieldentry", NULL, CLOZE_TEST_IDENTIFIER);
60 $a_xml_writer->xmlEndTag("qtimetadatafield");
61 $a_xml_writer->xmlStartTag("qtimetadatafield");
62 $a_xml_writer->xmlElement("fieldlabel", NULL, "AUTHOR");
63 $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getAuthor());
64 $a_xml_writer->xmlEndTag("qtimetadatafield");
65
66 // additional content editing information
68 $this->addGeneralMetadata($a_xml_writer);
69
70 $a_xml_writer->xmlStartTag("qtimetadatafield");
71 $a_xml_writer->xmlElement("fieldlabel", NULL, "textgaprating");
72 $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getTextgapRating());
73 $a_xml_writer->xmlEndTag("qtimetadatafield");
74
75 $a_xml_writer->xmlStartTag("qtimetadatafield");
76 $a_xml_writer->xmlElement("fieldlabel", NULL, "fixedTextLength");
77 $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getFixedTextLength());
78 $a_xml_writer->xmlEndTag("qtimetadatafield");
79
80 $a_xml_writer->xmlStartTag("qtimetadatafield");
81 $a_xml_writer->xmlElement("fieldlabel", NULL, "identicalScoring");
82 $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getIdenticalScoring());
83 $a_xml_writer->xmlEndTag("qtimetadatafield");
84
85 $a_xml_writer->xmlStartTag("qtimetadatafield");
86 $a_xml_writer->xmlElement("fieldlabel", NULL, "combinations");
87 $a_xml_writer->xmlElement("fieldentry", NULL, base64_encode(json_encode($this->object->getGapCombinations())));
88 $a_xml_writer->xmlEndTag("qtimetadatafield");
89
90 $a_xml_writer->xmlEndTag("qtimetadata");
91 $a_xml_writer->xmlEndTag("itemmetadata");
92
93 // PART I: qti presentation
94 $attrs = array(
95 "label" => $this->object->getTitle()
96 );
97 $a_xml_writer->xmlStartTag("presentation", $attrs);
98 // add flow to presentation
99 $a_xml_writer->xmlStartTag("flow");
100
101 $questionText = $this->object->getQuestion() ? $this->object->getQuestion() : '&nbsp;';
102 $this->object->addQTIMaterial($a_xml_writer, $questionText);
103
104 $text_parts = preg_split("/\[gap.*?\[\/gap\]/", $this->object->getClozeText());
105
106 // add material with question text to presentation
107 for ($i = 0; $i <= $this->object->getGapCount(); $i++)
108 {
109 $this->object->addQTIMaterial($a_xml_writer, $text_parts[$i]);
110
111 if ($i < $this->object->getGapCount())
112 {
113 // add gap
114 $gap = $this->object->getGap($i);
115 switch ($gap->getType())
116 {
117 case CLOZE_SELECT:
118 // comboboxes
119 $attrs = array(
120 "ident" => "gap_$i",
121 "rcardinality" => "Single"
122 );
123 $a_xml_writer->xmlStartTag("response_str", $attrs);
124 $solution = $this->object->getSuggestedSolution($i);
125 if (count($solution))
126 {
127 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
128 {
129 $attrs = array(
130 "label" => "suggested_solution"
131 );
132 $a_xml_writer->xmlStartTag("material", $attrs);
133 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
134 if (strcmp($matches[1], "") != 0)
135 {
136 $intlink = $solution["internal_link"];
137 }
138 $a_xml_writer->xmlElement("mattext", NULL, $intlink);
139 $a_xml_writer->xmlEndTag("material");
140 }
141 }
142
143 $attrs = array("shuffle" => ($gap->getShuffle() ? "Yes" : "No"));
144 $a_xml_writer->xmlStartTag("render_choice", $attrs);
145
146 // add answers
147 $shuffleState = $gap->getShuffle();
148 $gap->setShuffle(false);
149 $items = $gap->getItems();
150 $gap->setShuffle($shuffleState);
151 foreach ($items as $answeritem)
152 {
153 $attrs = array(
154 "ident" => $answeritem->getOrder()
155 );
156 $a_xml_writer->xmlStartTag("response_label", $attrs);
157 $a_xml_writer->xmlStartTag("material");
158 $a_xml_writer->xmlElement("mattext", NULL, $answeritem->getAnswertext());
159 $a_xml_writer->xmlEndTag("material");
160 $a_xml_writer->xmlEndTag("response_label");
161 }
162 $a_xml_writer->xmlEndTag("render_choice");
163 $a_xml_writer->xmlEndTag("response_str");
164 break;
165 case CLOZE_TEXT:
166 // text fields
167 $attrs = array(
168 "ident" => "gap_$i",
169 "rcardinality" => "Single"
170 );
171 $a_xml_writer->xmlStartTag("response_str", $attrs);
172 $solution = $this->object->getSuggestedSolution($i);
173 if (count($solution))
174 {
175 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
176 {
177 $attrs = array(
178 "label" => "suggested_solution"
179 );
180 $a_xml_writer->xmlStartTag("material", $attrs);
181 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
182 if (strcmp($matches[1], "") != 0)
183 {
184 $intlink = $solution["internal_link"];
185 }
186 $a_xml_writer->xmlElement("mattext", NULL, $intlink);
187 $a_xml_writer->xmlEndTag("material");
188 }
189 }
190 $attrs = array(
191 "fibtype" => "String",
192 "prompt" => "Box",
193 "columns" => $gap->getMaxWidth(),
194 "maxchars" => $gap->getGapSize()
195 );
196 $a_xml_writer->xmlStartTag("render_fib", $attrs);
197 $a_xml_writer->xmlEndTag("render_fib");
198 $a_xml_writer->xmlEndTag("response_str");
199 break;
200 case CLOZE_NUMERIC:
201 // numeric fields
202 $attrs = array(
203 "ident" => "gap_$i",
204 "numtype" => "Decimal",
205 "rcardinality" => "Single"
206 );
207 $a_xml_writer->xmlStartTag("response_num", $attrs);
208 $solution = $this->object->getSuggestedSolution($i);
209 if (count($solution))
210 {
211 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
212 {
213 $attrs = array(
214 "label" => "suggested_solution"
215 );
216 $a_xml_writer->xmlStartTag("material", $attrs);
217 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
218 if (strcmp($matches[1], "") != 0)
219 {
220 $intlink = $solution["internal_link"];
221 }
222 $a_xml_writer->xmlElement("mattext", NULL, $intlink);
223 $a_xml_writer->xmlEndTag("material");
224 }
225 }
226 $answeritem = $gap->getItem(0);
227 $attrs = array(
228 "fibtype" => "Decimal",
229 "prompt" => "Box",
230 "columns" => $gap->getMaxWidth(),
231 "maxchars" => $gap->getGapSize()
232 );
233 if (is_object($answeritem))
234 {
235 if ($eval->e($answeritem->getLowerBound()) !== FALSE)
236 {
237 $attrs["minnumber"] = $answeritem->getLowerBound();
238 }
239 if ($eval->e($answeritem->getUpperBound()) !== FALSE)
240 {
241 $attrs["maxnumber"] = $answeritem->getUpperBound();
242 }
243 }
244 $a_xml_writer->xmlStartTag("render_fib", $attrs);
245 $a_xml_writer->xmlEndTag("render_fib");
246 $a_xml_writer->xmlEndTag("response_num");
247 break;
248 }
249 }
250 }
251 $a_xml_writer->xmlEndTag("flow");
252 $a_xml_writer->xmlEndTag("presentation");
253
254 // PART II: qti resprocessing
255 $a_xml_writer->xmlStartTag("resprocessing");
256 $a_xml_writer->xmlStartTag("outcomes");
257 $a_xml_writer->xmlStartTag("decvar");
258 $a_xml_writer->xmlEndTag("decvar");
259 $a_xml_writer->xmlEndTag("outcomes");
260
261 // add response conditions
262 for ($i = 0; $i < $this->object->getGapCount(); $i++)
263 {
264 $gap = $this->object->getGap($i);
265 switch ($gap->getType())
266 {
267 case CLOZE_SELECT:
268 $shuffleState = $gap->getShuffle();
269 $gap->setShuffle(false);
270 $items = $gap->getItems();
271 $gap->setShuffle($shuffleState);
272 foreach ($items as $answer)
273 {
274 $attrs = array(
275 "continue" => "Yes"
276 );
277 $a_xml_writer->xmlStartTag("respcondition", $attrs);
278 // qti conditionvar
279 $a_xml_writer->xmlStartTag("conditionvar");
280
281 $attrs = array(
282 "respident" => "gap_$i"
283 );
284 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
285 $a_xml_writer->xmlEndTag("conditionvar");
286 // qti setvar
287 $attrs = array(
288 "action" => "Add"
289 );
290 $a_xml_writer->xmlElement("setvar", $attrs, $answer->getPoints());
291 // qti displayfeedback
292 $linkrefid = "";
293 $linkrefid = "$i" . "_Response_" . $answer->getOrder();
294 $attrs = array(
295 "feedbacktype" => "Response",
296 "linkrefid" => $linkrefid
297 );
298 $a_xml_writer->xmlElement("displayfeedback", $attrs);
299 $a_xml_writer->xmlEndTag("respcondition");
300 }
301 break;
302 case CLOZE_TEXT:
303 foreach ($gap->getItems() as $answer)
304 {
305 $attrs = array(
306 "continue" => "Yes"
307 );
308 $a_xml_writer->xmlStartTag("respcondition", $attrs);
309 // qti conditionvar
310 $a_xml_writer->xmlStartTag("conditionvar");
311 $attrs = array(
312 "respident" => "gap_$i"
313 );
314 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
315 $a_xml_writer->xmlEndTag("conditionvar");
316 // qti setvar
317 $attrs = array(
318 "action" => "Add"
319 );
320 $a_xml_writer->xmlElement("setvar", $attrs, $answer->getPoints());
321 // qti displayfeedback
322 $linkrefid = "$i" . "_Response_" . $answer->getOrder();
323 $attrs = array(
324 "feedbacktype" => "Response",
325 "linkrefid" => $linkrefid
326 );
327 $a_xml_writer->xmlElement("displayfeedback", $attrs);
328 $a_xml_writer->xmlEndTag("respcondition");
329 }
330 break;
331 case CLOZE_NUMERIC:
332 foreach ($gap->getItems() as $answer)
333 {
334 $attrs = array(
335 "continue" => "Yes"
336 );
337 $a_xml_writer->xmlStartTag("respcondition", $attrs);
338 // qti conditionvar
339 $a_xml_writer->xmlStartTag("conditionvar");
340 $attrs = array(
341 "respident" => "gap_$i"
342 );
343 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
344 $a_xml_writer->xmlEndTag("conditionvar");
345 // qti setvar
346 $attrs = array(
347 "action" => "Add"
348 );
349 $a_xml_writer->xmlElement("setvar", $attrs, $answer->getPoints());
350 // qti displayfeedback
351 $linkrefid = "$i" . "_Response_" . $answer->getOrder();
352 $attrs = array(
353 "feedbacktype" => "Response",
354 "linkrefid" => $linkrefid
355 );
356 $a_xml_writer->xmlElement("displayfeedback", $attrs);
357 $a_xml_writer->xmlEndTag("respcondition");
358 }
359 break;
360 }
361 }
362
363 $feedback_allcorrect = $this->object->feedbackOBJ->getGenericFeedbackExportPresentation(
364 $this->object->getId(), true
365 );
366 if (strlen($feedback_allcorrect))
367 {
368 $attrs = array(
369 "continue" => "Yes"
370 );
371 $a_xml_writer->xmlStartTag("respcondition", $attrs);
372 // qti conditionvar
373 $a_xml_writer->xmlStartTag("conditionvar");
374
375 for ($i = 0; $i < $this->object->getGapCount(); $i++)
376 {
377 $gap = $this->object->getGap($i);
378 $indexes = $gap->getBestSolutionIndexes();
379 if ($i > 0)
380 {
381 $a_xml_writer->xmlStartTag("and");
382 }
383 switch ($gap->getType())
384 {
385 case CLOZE_SELECT:
386 $k = 0;
387 foreach ($indexes as $key)
388 {
389 if ($k > 0)
390 {
391 $a_xml_writer->xmlStartTag("or");
392 }
393 $attrs = array(
394 "respident" => "gap_$i"
395 );
396 $answer = $gap->getItem($key);
397 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
398 if ($k > 0)
399 {
400 $a_xml_writer->xmlEndTag("or");
401 }
402 $k++;
403 }
404 break;
405 case CLOZE_TEXT:
406 $k = 0;
407 foreach ($indexes as $key)
408 {
409 if ($k > 0)
410 {
411 $a_xml_writer->xmlStartTag("or");
412 }
413 $attrs = array(
414 "respident" => "gap_$i"
415 );
416 $answer = $gap->getItem($key);
417 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
418 if ($k > 0)
419 {
420 $a_xml_writer->xmlEndTag("or");
421 }
422 $k++;
423 }
424 break;
425 case CLOZE_NUMERIC:
426 $k = 0;
427 foreach ($indexes as $key)
428 {
429 if ($k > 0)
430 {
431 $a_xml_writer->xmlStartTag("or");
432 }
433 $attrs = array(
434 "respident" => "gap_$i"
435 );
436 $answer = $gap->getItem($key);
437 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
438 if ($k > 0)
439 {
440 $a_xml_writer->xmlEndTag("or");
441 }
442 $k++;
443 }
444 break;
445 }
446 if ($i > 0)
447 {
448 $a_xml_writer->xmlEndTag("and");
449 }
450 }
451 $a_xml_writer->xmlEndTag("conditionvar");
452 // qti displayfeedback
453 $attrs = array(
454 "feedbacktype" => "Response",
455 "linkrefid" => "response_allcorrect"
456 );
457 $a_xml_writer->xmlElement("displayfeedback", $attrs);
458 $a_xml_writer->xmlEndTag("respcondition");
459 }
460 $feedback_onenotcorrect = $this->object->feedbackOBJ->getGenericFeedbackExportPresentation(
461 $this->object->getId(), false
462 );
463 if (strlen($feedback_onenotcorrect))
464 {
465 $attrs = array(
466 "continue" => "Yes"
467 );
468 $a_xml_writer->xmlStartTag("respcondition", $attrs);
469 // qti conditionvar
470 $a_xml_writer->xmlStartTag("conditionvar");
471
472 $a_xml_writer->xmlStartTag("not");
473 for ($i = 0; $i < $this->object->getGapCount(); $i++)
474 {
475 $gap = $this->object->getGap($i);
476 $indexes = $gap->getBestSolutionIndexes();
477 if ($i > 0)
478 {
479 $a_xml_writer->xmlStartTag("and");
480 }
481 switch ($gap->getType())
482 {
483 case CLOZE_SELECT:
484 $k = 0;
485 foreach ($indexes as $key)
486 {
487 if ($k > 0)
488 {
489 $a_xml_writer->xmlStartTag("or");
490 }
491 $attrs = array(
492 "respident" => "gap_$i"
493 );
494 $answer = $gap->getItem($key);
495 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
496 if ($k > 0)
497 {
498 $a_xml_writer->xmlEndTag("or");
499 }
500 $k++;
501 }
502 break;
503 case CLOZE_TEXT:
504 $k = 0;
505 foreach ($indexes as $key)
506 {
507 if ($k > 0)
508 {
509 $a_xml_writer->xmlStartTag("or");
510 }
511 $attrs = array(
512 "respident" => "gap_$i"
513 );
514 $answer = $gap->getItem($key);
515 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
516 if ($k > 0)
517 {
518 $a_xml_writer->xmlEndTag("or");
519 }
520 $k++;
521 }
522 break;
523 case CLOZE_NUMERIC:
524 $k = 0;
525 foreach ($indexes as $key)
526 {
527 if ($k > 0)
528 {
529 $a_xml_writer->xmlStartTag("or");
530 }
531 $attrs = array(
532 "respident" => "gap_$i"
533 );
534 $answer = $gap->getItem($key);
535 $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
536 if ($k > 0)
537 {
538 $a_xml_writer->xmlEndTag("or");
539 }
540 $k++;
541 }
542 break;
543 }
544 if ($i > 0)
545 {
546 $a_xml_writer->xmlEndTag("and");
547 }
548 }
549 $a_xml_writer->xmlEndTag("not");
550 $a_xml_writer->xmlEndTag("conditionvar");
551 // qti displayfeedback
552 $attrs = array(
553 "feedbacktype" => "Response",
554 "linkrefid" => "response_onenotcorrect"
555 );
556 $a_xml_writer->xmlElement("displayfeedback", $attrs);
557 $a_xml_writer->xmlEndTag("respcondition");
558 }
559
560 $a_xml_writer->xmlEndTag("resprocessing");
561
562 // PART III: qti itemfeedback
563 for ($i = 0; $i < $this->object->getGapCount(); $i++)
564 {
565 $gap = $this->object->getGap($i);
566 switch ($gap->getType())
567 {
568 case CLOZE_SELECT:
569 break;
570 case CLOZE_TEXT:
571 break;
572 case CLOZE_NUMERIC:
573 break;
574 }
575 /*foreach ($gap->getItems() as $answer)
576 {
577 $linkrefid = "$i" . "_Response_" . $answer->getOrder();
578 $attrs = array(
579 "ident" => $linkrefid,
580 "view" => "All"
581 );
582 $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
583 // qti flow_mat
584 $a_xml_writer->xmlStartTag("flow_mat");
585// $a_xml_writer->xmlStartTag("material");
586// $a_xml_writer->xmlElement("mattext");
587// $a_xml_writer->xmlEndTag("material");
588 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation(
589 $this->object->getId(), $index
590 );
591 $this->object->addQTIMaterial($a_xml_writer, $fb);
592 $a_xml_writer->xmlEndTag("flow_mat");
593 $a_xml_writer->xmlEndTag("itemfeedback");
594 }*/
595
596 $attrs = array(
597 "ident" => $i,
598 "view" => "All"
599 );
600 $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
601 // qti flow_mat
602 $a_xml_writer->xmlStartTag("flow_mat");
603 // $a_xml_writer->xmlStartTag("material");
604 // $a_xml_writer->xmlElement("mattext");
605 // $a_xml_writer->xmlEndTag("material");
606 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation(
607 $this->object->getId(), $i
608 );
609 $this->object->addQTIMaterial($a_xml_writer, $fb);
610 $a_xml_writer->xmlEndTag("flow_mat");
611 $a_xml_writer->xmlEndTag("itemfeedback");
612 }
613
614 if (strlen($feedback_allcorrect))
615 {
616 $attrs = array(
617 "ident" => "response_allcorrect",
618 "view" => "All"
619 );
620 $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
621 // qti flow_mat
622 $a_xml_writer->xmlStartTag("flow_mat");
623 $this->object->addQTIMaterial($a_xml_writer, $feedback_allcorrect);
624 $a_xml_writer->xmlEndTag("flow_mat");
625 $a_xml_writer->xmlEndTag("itemfeedback");
626 }
627 if (strlen($feedback_onenotcorrect))
628 {
629 $attrs = array(
630 "ident" => "response_onenotcorrect",
631 "view" => "All"
632 );
633 $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
634 // qti flow_mat
635 $a_xml_writer->xmlStartTag("flow_mat");
636 $this->object->addQTIMaterial($a_xml_writer, $feedback_onenotcorrect);
637 $a_xml_writer->xmlEndTag("flow_mat");
638 $a_xml_writer->xmlEndTag("itemfeedback");
639 }
640
641 $a_xml_writer->xmlEndTag("item");
642 $a_xml_writer->xmlEndTag("questestinterop");
643
644 $xml = $a_xml_writer->xmlDumpMem(FALSE);
645 if (!$a_include_header)
646 {
647 $pos = strpos($xml, "?>");
648 $xml = substr($xml, $pos + 2);
649 }
650 return $xml;
651 }
652}
653
654?>
Class for cloze question exports.
toXML($a_include_header=true, $a_include_binary=true, $a_shuffle=false, $test_output=false, $force_image_references=false)
Returns a QTI xml representation of the question.
Class for question exports.
addGeneralMetadata(ilXmlWriter $xmlwriter)
addAdditionalContentEditingModeInformation(ilXmlWriter $a_xml_writer)
adds a qti meta data field for ilias specific information of "additional content editing mode" (xml w...
XML writer class.
xmlHeader()
Writes xml header @access public.
const CLOZE_TEST_IDENTIFIER
Question identifier constants.
const CLOZE_NUMERIC
const CLOZE_SELECT
const CLOZE_TEXT
Cloze question constants.