ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilQTIParser.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
33{
34 public const IL_MO_PARSE_QTI = 1;
35 public const IL_MO_VERIFY_QTI = 2;
36
37 public bool $hasRootElement = false;
38
39 private readonly int $user_id;
40
44 public array $path = [];
45
49 public array $items = [];
50
51 public ?ilQTIItem $item = null;
52
56 public $depth;
57
58 public string $qti_element = "";
59
60 public bool $in_presentation = false;
61
62 public bool $in_response = false;
63
67 public $render_type = null;
68
70
71 public ?ilQTIMaterial $material = null;
72
73 public ?ilQTIMatimage $matimage = null;
74
75 public ?ilQTIResponse $response = null;
76
78
79 public ?ilQTIOutcomes $outcomes = null;
80
81 public ?ilQTIDecvar $decvar = null;
82
84
85 public ?ilQTISetvar $setvar = null;
86
88
90
94 public array $flow_mat = [];
95
96 public int $flow = 0;
97
99
100 public ?ilQTIMattext $mattext = null;
101
102 public bool $sametag = false;
103
104 public string $characterbuffer = "";
105
107
108 public int $parser_mode = 0;
109
113 public array $import_idents = [];
114
115 public int $qpl_id = 0;
116
117 public ?int $tst_id = null;
118
119 public ?ilObjTest $tst_object = null;
120
121 public bool $do_nothing = false;
122
123 public int $gap_index = 0;
124
128 public array $assessments = [];
129
131
133
135
136 public bool $in_assessment = false;
137
138 public ?ilQTISection $section = null;
139
143 public array $import_mapping = [];
144
145 public int $question_counter = 1;
146
147 public bool $in_itemmetadata = false;
148
149 public bool $in_objectives = false;
150
154 public array $founditems = [];
155
156 public bool $verifyroot = false;
157
158 public int $verifyqticomment = 0;
159
160 public int $verifymetadatafield = 0;
161
162 public int $verifyfieldlabel = 0;
163
164 public string $verifyfieldlabeltext = "";
165
166 public int $verifyfieldentry = 0;
167
168 public string $verifyfieldentrytext = "";
169
170 protected int $numImportedItems = 0;
171
173
174 protected bool $in_prensentation_material = false;
175
176 protected bool $ignoreItemsEnabled = false;
177
178 private ?ilQTIMatapplet $matapplet = null;
179
183 private array $metadata = ["label" => "", "entry" => ""];
184
186
187 protected ?string $questionSetType = null;
188
190
191 public function __construct(
192 private readonly string $importdir,
193 ?string $a_xml_file,
194 int $a_mode = self::IL_MO_PARSE_QTI,
195 int $a_qpl_id = 0,
196 array $import_idents = [],
197 private array $mappings = []
198 ) {
200 global $DIC;
201 $this->user_id = $DIC['ilUser']->getId();
202
203 $this->parser_mode = $a_mode;
204 $this->questionfiles = new QuestionFiles();
205 parent::__construct($a_xml_file);
206
207 $this->qpl_id = $a_qpl_id;
208 $this->lng = $DIC->language();
209 if ($import_idents !== []) {
210 $this->import_idents = $import_idents;
211 }
212
213 $this->depth = $this->createParserStorage();
214 }
215
216 public function isIgnoreItemsEnabled(): bool
217 {
219 }
220
221 public function setIgnoreItemsEnabled(bool $ignoreItemsEnabled): void
222 {
223 $this->ignoreItemsEnabled = $ignoreItemsEnabled;
224 }
225
226 public function getQuestionSetType(): ?string
227 {
229 }
230
231 protected function setQuestionSetType(string $questionSetType): void
232 {
233 $this->questionSetType = $questionSetType;
234 }
235
236 public function setTestObject(ilObjTest $tst_object): void
237 {
238 $this->tst_object = $tst_object;
239 $this->tst_id = $this->tst_object->getId();
240 }
241
242 public function getTestObject(): ilObjTest
243 {
244 return $this->tst_object;
245 }
246
254 public function setHandlers($a_xml_parser): void
255 {
256 xml_set_element_handler($a_xml_parser, $this->handlerBeginTag(...), $this->handlerEndTag(...));
257 xml_set_character_data_handler($a_xml_parser, $this->handlerCharacterData(...));
258 }
259
260 public function startParsing(): void
261 {
262 $this->question_counter = 1;
263 parent::startParsing();
264 }
265
269 public function getParent($a_xml_parser): string
270 {
271 if ($this->depth[$a_xml_parser] > 0) {
272 return $this->path[$this->depth[$a_xml_parser] - 1];
273 }
274
275 return "";
276 }
277
282 public function handlerBeginTag($a_xml_parser, string $a_name, array $a_attribs): void
283 {
284 switch ($this->parser_mode) {
286 $this->handlerParseBeginTag($a_xml_parser, $a_name, $a_attribs);
287 break;
289 $this->handlerVerifyBeginTag($a_xml_parser, $a_name, $a_attribs);
290 break;
291 }
292 }
293
298 public function handlerParseBeginTag($a_xml_parser, string $a_name, array $a_attribs): void
299 {
300 if ($this->do_nothing) {
301 return;
302 }
303 $this->sametag = false;
304 $this->characterbuffer = "";
305 $this->depth[$a_xml_parser] = ($this->depth[$a_xml_parser] ?? 0) + 1; // Issue with SplObjectStorage: Cannot use ++.
306 $this->path[$this->depth[$a_xml_parser]] = strtolower($a_name);
307 $this->qti_element = $a_name;
308
309 switch (strtolower($a_name)) {
310 case "assessment":
311 $this->assessmentBeginTag($a_attribs);
312 break;
313 case "assessmentcontrol":
314 $this->assessmentControlBeginTag($a_attribs);
315 break;
316 case "objectives":
317 $this->objectives = new ilQTIObjectives();
318 $this->in_objectives = true;
319 break;
320 case 'presentation_material':
321 $this->prensentation_material = new ilQTIPresentationMaterial();
322 $this->in_prensentation_material = true;
323 break;
324 case "section":
325 $this->section = new ilQTISection();
326 break;
327 case "itemmetadata":
328 $this->in_itemmetadata = true;
329 break;
330 case "qtimetadatafield":
331 $this->metadata = ["label" => "", "entry" => ""];
332 break;
333 case "flow":
334 $this->flow++;
335 break;
336 case "flow_mat":
337 $this->flow_mat[] = new ilQTIFlowMat();
338 break;
339 case "itemfeedback":
340 $this->itemFeedbackBeginTag($a_attribs);
341 break;
342 case "displayfeedback":
343 $this->displayFeedbackBeginTag($a_attribs);
344 break;
345 case "setvar":
346 $this->setVarBeginTag($a_attribs);
347 break;
348 case "conditionvar":
349 $this->conditionvar = new ilQTIConditionvar();
350 break;
351 case "not":
352 if ($this->conditionvar != null) {
353 $this->conditionvar->addNot();
354 }
355 break;
356 case "and":
357 if ($this->conditionvar != null) {
358 $this->conditionvar->addAnd();
359 }
360 break;
361 case "or":
362 if ($this->conditionvar != null) {
363 $this->conditionvar->addOr();
364 }
365 break;
366 case "varequal":
367 $this->varEqualBeginTag($a_attribs);
368 break;
369 case "varlt":
370 $this->responsevar = new ilQTIResponseVar(ilQTIResponseVar::RESPONSEVAR_LT);
371 foreach ($a_attribs as $attribute => $value) {
372 switch (strtolower($attribute)) {
373 case "respident":
374 $this->responsevar->setRespident($value);
375 break;
376 case "index":
377 $this->responsevar->setIndex($value);
378 break;
379 }
380 }
381 break;
382 case "varlte":
383 $this->responsevar = new ilQTIResponseVar(ilQTIResponseVar::RESPONSEVAR_LTE);
384 foreach ($a_attribs as $attribute => $value) {
385 switch (strtolower($attribute)) {
386 case "respident":
387 $this->responsevar->setRespident($value);
388 break;
389 case "index":
390 $this->responsevar->setIndex($value);
391 break;
392 }
393 }
394 break;
395 case "vargt":
396 $this->responsevar = new ilQTIResponseVar(ilQTIResponseVar::RESPONSEVAR_GT);
397 foreach ($a_attribs as $attribute => $value) {
398 switch (strtolower($attribute)) {
399 case "respident":
400 $this->responsevar->setRespident($value);
401 break;
402 case "index":
403 $this->responsevar->setIndex($value);
404 break;
405 }
406 }
407 break;
408 case "vargte":
409 $this->responsevar = new ilQTIResponseVar(ilQTIResponseVar::RESPONSEVAR_GTE);
410 foreach ($a_attribs as $attribute => $value) {
411 switch (strtolower($attribute)) {
412 case "respident":
413 $this->responsevar->setRespident($value);
414 break;
415 case "index":
416 $this->responsevar->setIndex($value);
417 break;
418 }
419 }
420 break;
421 case "varsubset":
423 foreach ($a_attribs as $attribute => $value) {
424 switch (strtolower($attribute)) {
425 case "respident":
426 $this->responsevar->setRespident($value);
427 break;
428 case "setmatch":
429 $this->responsevar->setSetmatch($value);
430 break;
431 case "index":
432 $this->responsevar->setIndex($value);
433 break;
434 }
435 }
436 break;
437 case "varinside":
439 foreach ($a_attribs as $attribute => $value) {
440 switch (strtolower($attribute)) {
441 case "respident":
442 $this->responsevar->setRespident($value);
443 break;
444 case "areatype":
445 $this->responsevar->setAreatype($value);
446 break;
447 case "index":
448 $this->responsevar->setIndex($value);
449 break;
450 }
451 }
452 break;
453 case "varsubstring":
455 foreach ($a_attribs as $attribute => $value) {
456 switch (strtolower($attribute)) {
457 case "case":
458 $this->responsevar->setCase($value);
459 break;
460 case "respident":
461 $this->responsevar->setRespident($value);
462 break;
463 case "index":
464 $this->responsevar->setIndex($value);
465 break;
466 }
467 }
468 break;
469 case "respcondition":
470 $this->respcondition = new ilQTIRespcondition();
471 foreach ($a_attribs as $attribute => $value) {
472 switch (strtolower($attribute)) {
473 case "continue":
474 $this->respcondition->setContinue($value);
475 break;
476 case "title":
477 $this->respcondition->setTitle($value);
478 break;
479 }
480 }
481 break;
482 case "outcomes":
483 $this->outcomes = new ilQTIOutcomes();
484 break;
485 case "decvar":
486 $this->decVarBeginTag($a_attribs);
487 break;
488 case "matimage":
489 $this->matImageBeginTag($a_attribs);
490 break;
491 case "material":
492 $this->materialBeginTag($a_attribs);
493 break;
494 case "mattext":
495 $this->matTextBeginTag($a_attribs);
496 break;
497 case "matapplet":
498 $this->matAppletBeginTag($a_attribs);
499 break;
500 case "questestinterop":
501 $this->hasRootElement = true;
502 break;
503 case "qticomment":
504 break;
505 case "objectbank":
506 // not implemented yet
507 break;
508 case "presentation":
509 $this->in_presentation = true;
510 $this->presentation = new ilQTIPresentation();
511 break;
512 case "response_label":
513 $this->responseLabelBeginTag($a_attribs);
514 break;
515 case "render_choice":
516 $this->renderChoiceBeginTag($a_attribs);
517 break;
518 case "render_hotspot":
519 $this->renderHotspotBeginTag($a_attribs);
520 break;
521 case "render_fib":
522 $this->renderFibBeginTag($a_attribs);
523 break;
524 case "response_lid":
525 // Ordering Terms and Definitions or
526 // Ordering Terms and Pictures or
527 // Multiple choice single response or
528 // Multiple choice multiple response
529 case "response_xy":
530 // Imagemap question
531 case "response_str":
532 // Close question
533 case "response_num":
534 case "response_grp":
535 // Matching terms and definitions
536 // Matching terms and images
537 $this->termsAndDefinitionsBeginTag($a_name, $a_attribs);
538 break;
539 case "item":
540 $this->itemBeginTag($a_attribs);
541 break;
542 case "resprocessing":
543 $this->resprocessingBeginTag($a_attribs);
544 break;
545 }
546 }
547
551 public function handlerEndTag($a_xml_parser, string $a_name): void
552 {
553 switch ($this->parser_mode) {
555 $this->handlerParseEndTag($a_xml_parser, $a_name);
556 break;
558 $this->handlerVerifyEndTag($a_xml_parser, $a_name);
559 break;
560 }
561 }
562
567 public function handlerParseEndTag($a_xml_parser, string $a_name): void
568 {
569 if ($this->do_nothing && strtolower($a_name) !== "item") {
570 return;
571 }
572 switch (strtolower($a_name)) {
573 case "assessment":
574 if (is_object($this->tst_object)) {
575 $this->tst_object->fromXML($this->assessment, $this->mappings);
576 }
577 $this->in_assessment = false;
578 break;
579 case "assessmentcontrol":
580 $this->assessment->addAssessmentcontrol($this->assessmentcontrol);
581 $this->assessmentcontrol = null;
582 break;
583 case "objectives":
584 if (strtolower($this->getParent($a_xml_parser)) === "assessment") {
585 $this->assessment->addObjectives($this->objectives);
586 }
587 $this->in_objectives = false;
588 break;
589 case 'presentation_material':
590 $this->assessment->setPresentationMaterial($this->prensentation_material);
591 $this->in_prensentation_material = false;
592 break;
593 case "itemmetadata":
594 $this->in_itemmetadata = false;
595 break;
596 case "qtimetadatafield":
597 // handle only specific ILIAS metadata
598 switch ($this->metadata["label"]) {
599 case "ILIAS_VERSION":
600 if ($this->item !== null) {
601 $this->item->setIliasSourceVersion(
602 $this->fetchNumericVersionFromVersionDateString($this->metadata["entry"])
603 );
604 }
605 break;
606 case "QUESTIONTYPE":
607 if ($this->item !== null) {
608 $this->item->setQuestiontype($this->metadata["entry"]);
609 }
610 break;
611 case "AUTHOR":
612 if ($this->item !== null) {
613 $this->item->setAuthor($this->metadata["entry"]);
614 }
615 // no break
616 default:
617 if ($this->item !== null) {
618 $this->item->addMetadata($this->metadata);
619 }
620 break;
621 }
622 if ($this->in_assessment) {
623 $this->assessment->addQtiMetadata($this->metadata);
624 }
625 $this->metadata = ["label" => "", "entry" => ""];
626 break;
627 case "flow":
628 $this->flow--;
629 break;
630 case "flow_mat":
631 if (count($this->flow_mat)) {
632 $flow_mat = array_pop($this->flow_mat);
633 if (count($this->flow_mat)) {
634 $this->flow_mat[count($this->flow_mat) - 1]->addFlowMat($flow_mat);
635 } elseif ($this->in_prensentation_material) {
636 $this->prensentation_material->addFlowMat($flow_mat);
637 } elseif ($this->itemfeedback != null) {
638 $this->itemfeedback->addFlowMat($flow_mat);
639 } elseif ($this->response_label != null) {
640 $this->response_label->addFlow_mat($flow_mat);
641 }
642 }
643 break;
644 case "itemfeedback":
645 if ($this->item != null) {
646 if ($this->itemfeedback != null) {
647 $this->item->addItemfeedback($this->itemfeedback);
648 }
649 }
650 $this->itemfeedback = null;
651 break;
652 case "displayfeedback":
653 if ($this->respcondition != null) {
654 if ($this->displayfeedback != null) {
655 $this->respcondition->addDisplayfeedback($this->displayfeedback);
656 }
657 }
658 $this->displayfeedback = null;
659 break;
660 case "setvar":
661 if ($this->respcondition !== null) {
662 if ($this->setvar != null) {
663 $this->respcondition->addSetvar($this->setvar);
664 }
665 }
666 $this->setvar = null;
667 break;
668 case "conditionvar":
669 if ($this->respcondition !== null) {
670 $this->respcondition->setConditionvar($this->conditionvar);
671 }
672 $this->conditionvar = null;
673 break;
674 case "varequal":
675 case "varlt":
676 case "varlte":
677 case "vargt":
678 case "vargte":
679 case "varsubset":
680 case "varinside":
681 case "varsubstring":
682 if ($this->conditionvar != null) {
683 if ($this->responsevar != null) {
684 $this->conditionvar->addResponseVar($this->responsevar);
685 }
686 }
687 $this->responsevar = null;
688 break;
689 case "respcondition":
690 if ($this->resprocessing != null) {
691 $this->resprocessing->addRespcondition($this->respcondition);
692 }
693 $this->respcondition = null;
694 break;
695 case "outcomes":
696 if ($this->resprocessing != null) {
697 $this->resprocessing->setOutcomes($this->outcomes);
698 }
699 $this->outcomes = null;
700 break;
701 case "decvar":
702 if ($this->outcomes != null) {
703 $this->outcomes->addDecvar($this->decvar);
704 }
705 $this->decvar = null;
706 break;
707 case "presentation":
708 $this->in_presentation = false;
709 if ($this->presentation != null && $this->item != null) {
710 $this->item->setPresentation($this->presentation);
711 }
712 $this->presentation = null;
713 break;
714 case "response_label":
715 if ($this->render_type != null) {
716 $this->render_type->addResponseLabel($this->response_label);
717 $this->response_label = null;
718 }
719 break;
720 case "render_choice":
721 case "render_hotspot":
722 case "render_fib":
723 if ($this->in_response) {
724 if ($this->response != null) {
725 if ($this->render_type != null) {
726 $this->response->setRenderType($this->render_type);
727 $this->render_type = null;
728 }
729 }
730 }
731 break;
732 case "response_lid":
733 case "response_xy":
734 case "response_str":
735 case "response_num":
736 case "response_grp":
737 $this->gap_index++;
738 if ($this->presentation != null) {
739 if ($this->response != null) {
740 $this->presentation->addResponse($this->response);
741 if ($this->item != null) {
742 $this->item->addPresentationitem($this->response);
743 }
744 }
745 }
746 $this->response = null;
747 $this->in_response = false;
748 break;
749 case "item":
750 if ($this->do_nothing) {
751 $this->do_nothing = false;
752 return;
753 }
754 // save the item directly to save memory
755 // the database id's of the created items are exported. if the import fails
756 // ILIAS can delete the already imported items
757
758 // problems: the object id of the parent questionpool is not yet known. must be set later
759 // the complete flag must be calculated?
760 $qt = $this->item->determineQuestionType();
761 $presentation = $this->item->getPresentation();
762
764 return;
765 }
766
767 $question = new $qt();
768 $fbt = str_replace('ass', 'ilAss', $qt) . 'Feedback';
769 $question->feedbackOBJ = new $fbt(
770 $question,
771 $GLOBALS['ilCtrl'],
772 $GLOBALS['ilDB'],
773 $GLOBALS['lng']
774 );
775 $this->import_mapping = $question->fromXML(
776 $this->importdir,
777 $this->user_id,
778 $this->item,
779 $this->qpl_id,
780 $this->tst_id,
781 $this->tst_object,
782 $this->question_counter,
783 $this->import_mapping,
784 );
785
786 $this->numImportedItems++;
787
788 break;
789 case "material":
790 if ($this->material) {
791 $mat = $this->material->getMaterial(0);
792 if (!is_array($mat)) {
793 $this->material = null;
794 break;
795 }
796 if ($mat["type"] === "mattext" && $mat["material"]->getLabel() === "suggested_solution") {
797 $this->item->addSuggestedSolution($mat["material"], $this->gap_index);
798 }
799 if ($this->in_objectives) {
800 $this->objectives->addMaterial($this->material);
801 } elseif ($this->render_type != null && strtolower($this->getParent($a_xml_parser)) === "render_hotspot") {
802 $this->render_type->addMaterial($this->material);
803 } elseif (count($this->flow_mat) && strtolower($this->getParent($a_xml_parser)) === "flow_mat") {
804 $this->flow_mat[count($this->flow_mat) - 1]->addMaterial($this->material);
805 } elseif ($this->itemfeedback != null) {
806 $this->itemfeedback->addMaterial($this->material);
807 } elseif ($this->response_label != null) {
808 $this->response_label->addMaterial($this->material);
809 } elseif ($this->response != null) {
810 if ($this->response->hasRendering()) {
811 $this->response->setMaterial2($this->material);
812 } else {
813 $this->response->setMaterial1($this->material);
814 }
815 } elseif (($this->in_presentation) && (!$this->in_response)) {
816 if (!is_object($this->item->getQuestiontext())) {
817 $this->item->setQuestiontext($this->material);
818 }
819 $this->presentation->addMaterial($this->material);
820 } elseif ($this->presentation != null) {
821 $this->presentation->addMaterial($this->material);
822 if ($this->item != null) {
823 $this->item->addPresentationitem($this->material);
824 }
825 }
826 }
827 $this->material = null;
828 break;
829 case "matimage":
830
831 if (!$this->isMatImageAvailable()) {
832 break;
833 }
834
835 if ($this->virusDetected($this->matimage->getRawContent())) {
836 break;
837 }
838 try {
839 $matImageSecurity = new ilQtiMatImageSecurity($this->matimage, $this->questionfiles);
840 $matImageSecurity->sanitizeLabel();
841 } catch (Exception $e) {
842 break;
843 }
844 if (!$matImageSecurity->validate()) {
845 break;
846 }
847
848 $this->material->addMatimage($this->matimage);
849 $this->matimage = null;
850 break;
851
852 // add support for matbreak element
853 case "matbreak":
854 $this->mattext = new ilQTIMattext();
855 $this->mattext->setContent('<br />');
856 $this->material->addMattext($this->mattext);
857 $this->mattext = null;
858 break;
859 case "resprocessing":
860 if ($this->item != null) {
861 $this->item->addResprocessing($this->resprocessing);
862 }
863 $this->resprocessing = null;
864 break;
865 case "mattext":
866 if ($this->material != null) {
867 $this->material->addMattext($this->mattext);
868 }
869 $this->mattext = null;
870 break;
871 case "matapplet":
872 if ($this->material != null) {
873 $this->material->addMatapplet($this->matapplet);
874 }
875 $this->matapplet = null;
876 break;
877 }
878 $this->depth[$a_xml_parser] -= 1; // Issue with SplObjectStorage: Cannot use --.
879 }
880
884 public function handlerCharacterData($a_xml_parser, string $a_data): void
885 {
886 switch ($this->parser_mode) {
888 $this->handlerParseCharacterData($a_xml_parser, $a_data);
889 break;
891 $this->handlerVerifyCharacterData($a_xml_parser, $a_data);
892 break;
893 }
894 }
895
899 public function handlerParseCharacterData($a_xml_parser, string $a_data): void
900 {
901 if ($this->do_nothing) {
902 return;
903 }
904 $this->characterbuffer .= $a_data;
905 $a_data = $this->characterbuffer;
906 switch ($this->qti_element) {
907 case "fieldlabel":
908 $this->metadata["label"] = $a_data;
909 break;
910 case "fieldentry":
911 $this->metadata["entry"] = $a_data;
912 break;
913 case "response_label":
914 if ($this->response_label != null) {
915 $this->response_label->setContent($a_data);
916 }
917 break;
918 case "setvar":
919 if ($this->setvar != null) {
920 $this->setvar->setContent($a_data);
921 }
922 break;
923 case "displayfeedback":
924 if ($this->displayfeedback != null) {
925 $this->displayfeedback->setContent($a_data);
926 }
927 break;
928 case "varequal":
929 case "varlt":
930 case "varlte":
931 case "vargt":
932 case "vargte":
933 case "varsubset":
934 case "varinside":
935 case "varsubstring":
936 if ($this->responsevar != null) {
937 $this->responsevar->setContent($a_data);
938 }
939 break;
940 case "decvar":
941 if (strlen($a_data)) {
942 if ($this->decvar != null) {
943 $this->decvar->setContent($a_data);
944 }
945 }
946 break;
947 case "mattext":
948 if ($this->mattext != null) {
949 $this->mattext->setContent($a_data);
950 }
951 break;
952 case "matapplet":
953 if ($this->matapplet != null) {
954 $this->matapplet->setContent($a_data);
955 }
956 break;
957 case "matimage":
958 if ($this->matimage != null) {
959 $this->matimage->setContent($a_data);
960 }
961 break;
962 case "duration":
963 switch ($this->getParent($a_xml_parser)) {
964 case "assessment":
965 // to be done
966 break;
967 case "section":
968 // to be done
969 break;
970 case "item":
971 $this->item->setDuration($a_data);
972 break;
973 }
974 break;
975 case "qticomment":
976 switch ($this->getParent($a_xml_parser)) {
977 case "item":
978 $this->item->setComment($a_data);
979 break;
980 case "assessment":
981 $this->assessment->setComment($a_data);
982 break;
983 default:
984 break;
985 }
986 break;
987 }
988 $this->sametag = true;
989 }
990
995 public function handlerVerifyBeginTag($a_xml_parser, string $a_name, array $a_attribs): void
996 {
997 $this->qti_element = $a_name;
998
999 switch (strtolower($a_name)) {
1000 case "assessment":
1001 $this->assessment = $this->assessments[] = new ilQTIAssessment();
1002 $this->in_assessment = true;
1003 foreach ($a_attribs as $attribute => $value) {
1004 switch (strtolower($attribute)) {
1005 case "title":
1006 $this->assessment->setTitle($value);
1007 break;
1008 case "ident":
1009 $this->assessment->setIdent($value);
1010 break;
1011 }
1012 }
1013 break;
1014 case "questestinterop":
1015 $this->verifyroot = true;
1016 break;
1017 case "qtimetadatafield":
1018 $this->metadata = ["label" => "", "entry" => ""];
1019 $this->verifymetadatafield = 1;
1020 break;
1021 case "fieldlabel":
1022 $this->verifyfieldlabeltext = "";
1023 if ($this->verifymetadatafield == 1) {
1024 $this->verifyfieldlabel = 1;
1025 }
1026 break;
1027 case "fieldentry":
1028 $this->verifyfieldentrytext = "";
1029 if ($this->verifymetadatafield == 1) {
1030 $this->verifyfieldentry = 1;
1031 }
1032 break;
1033 case "item":
1034 $title = "";
1035 foreach ($a_attribs as $attribute => $value) {
1036 switch (strtolower($attribute)) {
1037 case "title":
1038 $title = $value;
1039 break;
1040 }
1041 }
1042 $this->founditems[] = ["title" => "$title", "type" => "", "ident" => $a_attribs["ident"]];
1043 break;
1044 case "response_lid":
1045 if ($this->founditems[count($this->founditems) - 1]['type'] === '') {
1046 // test for non ILIAS generated question types
1047 foreach ($a_attribs as $attribute => $value) {
1048 switch (strtolower($attribute)) {
1049 case "rcardinality":
1050 switch (strtolower($value)) {
1051 case "single":
1052 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_MULTIPLE_CHOICE_SR;
1053 break;
1054 case "multiple":
1055 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_MULTIPLE_CHOICE_MR;
1056 break;
1057 case "ordered":
1058 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_ORDERING;
1059 break;
1060 }
1061 break;
1062 }
1063 }
1064 }
1065 break;
1066
1067 case "response_str":
1068 if (strlen($this->founditems[count($this->founditems) - 1]["type"]) == 0) {
1069 // test for non ILIAS generated question types
1070 foreach ($a_attribs as $attribute => $value) {
1071 switch (strtolower($attribute)) {
1072 case "rcardinality":
1073 switch (strtolower($value)) {
1074 case "single":
1075 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_CLOZE;
1076 break;
1077 case "ordered":
1078 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_TEXT;
1079 break;
1080 }
1081 break;
1082 }
1083 }
1084 }
1085 break;
1086 case "response_xy":
1087 if (strlen($this->founditems[count($this->founditems) - 1]["type"]) == 0) {
1088 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_IMAGEMAP;
1089 }
1090 break;
1091 case "response_num":
1092 if (strlen($this->founditems[count($this->founditems) - 1]["type"]) == 0) {
1093 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_NUMERIC;
1094 }
1095 break;
1096 case "response_grp":
1097 if (strlen($this->founditems[count($this->founditems) - 1]["type"]) == 0) {
1098 $this->founditems[count($this->founditems) - 1]["type"] = ilQTIItem::QT_MATCHING;
1099 }
1100 break;
1101 case "qticomment":
1102 // check for "old" ILIAS qti format (not well formed)
1103 $this->verifyqticomment = 1;
1104 break;
1105 case "presentation":
1106 foreach ($a_attribs as $attribute => $value) {
1107 switch (strtolower($attribute)) {
1108 case "label":
1109 $this->founditems[count($this->founditems) - 1]["title"] = $value;
1110 break;
1111 }
1112 }
1113 break;
1114 }
1115 }
1116
1120 public function handlerVerifyEndTag($a_xml_parser, string $a_name): void
1121 {
1122 switch (strtolower($a_name)) {
1123 case "assessment":
1124 foreach ($this->assessment->qtimetadata as $metaField) {
1125 if ($metaField['label'] == 'question_set_type') {
1126 $this->setQuestionSetType($metaField['entry']);
1127 break;
1128 }
1129
1130 if ($metaField['label'] == 'random_test') {
1131 if ($metaField['entry'] == 1) {
1133 } else {
1135 }
1136 break;
1137 }
1138 }
1139 $this->in_assessment = false;
1140 break;
1141 case "qticomment":
1142 // check for "old" ILIAS qti format (not well formed)
1143 $this->verifyqticomment = 0;
1144 break;
1145 case "qtimetadatafield":
1146 $this->verifymetadatafield = 0;
1147 if ($this->verifyfieldlabeltext === "QUESTIONTYPE") {
1148 $this->founditems[count($this->founditems) - 1]["type"] = $this->verifyfieldentrytext;
1149 }
1150 if ($this->in_assessment) {
1151 $this->assessment->addQtiMetadata($this->metadata);
1152 }
1153 $this->metadata = ["label" => "", "entry" => ""];
1154 break;
1155 case "fieldlabel":
1156 $this->verifyfieldlabel = 0;
1157 break;
1158 case "fieldentry":
1159 $this->verifyfieldentry = 0;
1160 break;
1161 }
1162 }
1163
1167 public function handlerVerifyCharacterData($a_xml_parser, string $a_data): void
1168 {
1169 if ($this->verifyqticomment == 1) {
1170 if (preg_match("/Questiontype\=(.*)/", $a_data, $matches)) {
1171 if (count($this->founditems)) {
1172 $this->founditems[count($this->founditems) - 1]["type"] = $matches[1];
1173 }
1174 }
1175 } elseif ($this->verifyfieldlabel == 1) {
1176 $this->verifyfieldlabeltext = $a_data;
1177 } elseif ($this->verifyfieldentry == 1) {
1178 $this->verifyfieldentrytext = $a_data;
1179 }
1180
1181 switch ($this->qti_element) {
1182 case "fieldlabel":
1183 $this->metadata["label"] = $a_data;
1184 break;
1185 case "fieldentry":
1186 $this->metadata["entry"] = $a_data;
1187 break;
1188 }
1189 }
1190
1194 public function &getFoundItems(): array
1195 {
1196 return $this->founditems;
1197 }
1198
1203 public function getImportMapping(): array
1204 {
1205 return $this->import_mapping;
1206 }
1207
1211 public function getQuestionIdMapping(): array
1212 {
1213 $questionIdMapping = [];
1214
1215 foreach ($this->getImportMapping() as $k => $v) {
1216 $oldQuestionId = substr($k, strpos($k, 'qst_') + strlen('qst_'));
1217 $newQuestionId = $v['test']; // yes, this is the new question id ^^
1218
1219 $questionIdMapping[$oldQuestionId] = $newQuestionId;
1220 }
1221
1222 return $questionIdMapping;
1223 }
1224
1225 public function setXMLContent(string $a_xml_content): void
1226 {
1227 $a_xml_content = $this->cleanInvalidXmlChars($a_xml_content);
1228
1229 parent::setXMLContent($a_xml_content);
1230 }
1231
1235 protected function openXMLFile()
1236 {
1237 $xmlContent = file_get_contents($this->xml_file);
1238 $xmlContent = $this->cleanInvalidXmlChars($xmlContent);
1239 file_put_contents($this->xml_file, $xmlContent);
1240
1241 return parent::openXMLFile();
1242 }
1243
1244 protected function fetchNumericVersionFromVersionDateString(string $versionDateString): ?string
1245 {
1246 $matches = null;
1247
1248 if (preg_match('/^(\d+\.\d+\.\d+)$/', $versionDateString, $matches)) {
1249 return $matches[1];
1250 }
1251
1252 return null;
1253 }
1254
1255 protected function fetchSourceNicFromItemIdent(string $itemIdent): ?string
1256 {
1257 $matches = null;
1258
1259 if (preg_match('/^il_(\d+?)_qst_\d+$/', $itemIdent, $matches)) {
1260 return $matches[1];
1261 }
1262
1263 return null;
1264 }
1265
1266 protected function cleanInvalidXmlChars(string $xmlContent): string
1267 {
1268 // http://www.w3.org/TR/xml/#charsets
1269
1270 // DOES ACTUALLY KILL CONTENT, SHOULD CLEAN NON ESCAPED ILLEGAL CHARS, DON'T KNOW
1271 //$reg = '/[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]/';
1272 //$xmlContent = preg_replace($reg, '', $xmlContent);
1273
1274 // remove illegal chars escaped to html entities
1275 $needles = [];
1276 for ($i = 0x00, $max = 0x08; $i <= $max; $i += 0x01) {
1277 $needles[] = "&#{$i};";
1278 }
1279 for ($i = 0x0b, $max = 0x0c; $i <= $max; $i += 0x01) {
1280 $needles[] = "&#{$i};";
1281 }
1282 for ($i = 0x0e, $max = 0x1f; $i <= $max; $i += 0x01) {
1283 $needles[] = "&#{$i};";
1284 }
1285 for ($i = 0xd800, $max = 0xdfff; $i <= $max; $i += 0x0001) {
1286 $needles[] = "&#{$i};";
1287 }
1288 for ($i = 0xfffe, $max = 0xffff; $i <= $max; $i += 0x0001) {
1289 $needles[] = "&#{$i};";
1290 }
1291 $reg = '/(' . implode('|', $needles) . ')/';
1292 $xmlContent = preg_replace($reg, '', $xmlContent);
1293
1294 return $xmlContent;
1295 }
1296
1297 public function getNumImportedItems(): int
1298 {
1300 }
1301
1302 protected function isMatImageAvailable(): bool
1303 {
1304 if (!$this->material) {
1305 return false;
1306 }
1307
1308 if (!$this->matimage) {
1309 return false;
1310 }
1311
1312 return true;
1313 }
1314
1315 protected function virusDetected(string $buffer): bool
1316 {
1318
1319 if ($vs === null) {
1320 return false; // no virus scan, no virus detected
1321 }
1322
1323 return $vs->scanBuffer($buffer);
1324 }
1325
1326 private function assessmentBeginTag(array $a_attribs): void
1327 {
1328 $this->assessment = $this->assessments[] = new ilQTIAssessment();
1329 $this->in_assessment = true;
1330 foreach ($a_attribs as $attribute => $value) {
1331 switch (strtolower($attribute)) {
1332 case "title":
1333 $this->assessment->setTitle($value);
1334 break;
1335 case "ident":
1336 $this->assessment->setIdent($value);
1337 break;
1338 }
1339 }
1340 }
1341
1342 private function assessmentControlBeginTag(array $a_attribs): void
1343 {
1344 $this->assessmentcontrol = new ilQTIAssessmentcontrol();
1345 foreach ($a_attribs as $attribute => $value) {
1346 switch (strtolower($attribute)) {
1347 case "solutionswitch":
1348 $this->assessmentcontrol->setSolutionswitch($value);
1349 break;
1350 case "hintswitch":
1351 $this->assessmentcontrol->setHintswitch($value);
1352 break;
1353 case "feedbackswitch":
1354 $this->assessmentcontrol->setFeedbackswitch($value);
1355 break;
1356 }
1357 }
1358 }
1359
1360 private function itemFeedbackBeginTag(array $a_attribs): void
1361 {
1362 $this->itemfeedback = new ilQTIItemfeedback();
1363 foreach ($a_attribs as $attribute => $value) {
1364 switch (strtolower($attribute)) {
1365 case "ident":
1366 $this->itemfeedback->setIdent($value);
1367 break;
1368 case "view":
1369 $this->itemfeedback->setView($value);
1370 break;
1371 }
1372 }
1373 }
1374
1375 private function displayFeedbackBeginTag(array $a_attribs): void
1376 {
1377 $this->displayfeedback = new ilQTIDisplayfeedback();
1378 foreach ($a_attribs as $attribute => $value) {
1379 switch (strtolower($attribute)) {
1380 case "feedbacktype":
1381 $this->displayfeedback->setFeedbacktype($value);
1382 break;
1383 case "linkrefid":
1384 $this->displayfeedback->setLinkrefid($value);
1385 break;
1386 }
1387 }
1388 }
1389
1390 private function setVarBeginTag(array $a_attribs): void
1391 {
1392 $this->setvar = new ilQTISetvar();
1393 foreach ($a_attribs as $attribute => $value) {
1394 switch (strtolower($attribute)) {
1395 case "action":
1396 $this->setvar->setAction($value);
1397 break;
1398 case "varname":
1399 $this->setvar->setVarname($value);
1400 break;
1401 }
1402 }
1403 }
1404
1405 private function varEqualBeginTag(array $a_attribs): void
1406 {
1407 $this->responsevar = new ilQTIResponseVar(ilQTIResponseVar::RESPONSEVAR_EQUAL);
1408 foreach ($a_attribs as $attribute => $value) {
1409 switch (strtolower($attribute)) {
1410 case "case":
1411 $this->responsevar->setCase($value);
1412 break;
1413 case "respident":
1414 $this->responsevar->setRespident($value);
1415 break;
1416 case "index":
1417 $this->responsevar->setIndex($value);
1418 break;
1419 }
1420 }
1421 }
1422
1423 private function termsAndDefinitionsBeginTag(string $a_name, array $a_attribs): void
1424 {
1425 $response_type = 0;
1426 switch (strtolower($a_name)) {
1427 case "response_lid":
1428 $response_type = ilQTIResponse::RT_RESPONSE_LID;
1429 break;
1430 case "response_xy":
1431 $response_type = ilQTIResponse::RT_RESPONSE_XY;
1432 break;
1433 case "response_str":
1434 $response_type = ilQTIResponse::RT_RESPONSE_STR;
1435 break;
1436 case "response_num":
1437 $response_type = ilQTIResponse::RT_RESPONSE_NUM;
1438 break;
1439 case "response_grp":
1440 $response_type = ilQTIResponse::RT_RESPONSE_GRP;
1441 break;
1442 }
1443 $this->in_response = true;
1444 $this->response = new ilQTIResponse($response_type);
1445 $this->response->setFlow($this->flow);
1446 foreach ($a_attribs as $attribute => $value) {
1447 switch (strtolower($attribute)) {
1448 case "ident":
1449 $this->response->setIdent($value);
1450 break;
1451 case "rtiming":
1452 $this->response->setRTiming($value);
1453 break;
1454 case "rcardinality":
1455 $this->response->setRCardinality($value);
1456 break;
1457 case "numtype":
1458 $this->response->setNumtype($value);
1459 break;
1460 }
1461 }
1462 }
1463
1464 private function itemBeginTag(array $a_attribs): void
1465 {
1466 $this->gap_index = 0;
1467 $this->item = $this->items[] = new ilQTIItem();
1468 foreach ($a_attribs as $attribute => $value) {
1469 switch (strtolower($attribute)) {
1470 case "ident":
1471 $this->item->setIdent($value);
1472 $this->item->setIliasSourceNic(
1473 $this->fetchSourceNicFromItemIdent($value)
1474 );
1475 if ($this->isIgnoreItemsEnabled()) {
1476 $this->do_nothing = true;
1477 } elseif ($this->import_idents !== []
1478 && !in_array($value, $this->import_idents)) {
1479 $this->do_nothing = true;
1480 }
1481 break;
1482 case "title":
1483 $this->item->setTitle($value);
1484 break;
1485 case "maxattempts":
1486 $this->item->setMaxattempts($value);
1487 break;
1488 }
1489 }
1490 }
1491
1492 private function resprocessingBeginTag(array $a_attribs): void
1493 {
1494 $this->resprocessing = new ilQTIResprocessing();
1495 foreach ($a_attribs as $attribute => $value) {
1496 switch (strtolower($attribute)) {
1497 case "scoremodel":
1498 $this->resprocessing->setScoremodel($value);
1499 break;
1500 }
1501 }
1502 }
1503
1504 private function renderFibBeginTag(array $a_attribs): void
1505 {
1506 if (!$this->in_response) {
1507 return;
1508 }
1509 $this->render_type = new ilQTIRenderFib();
1510 foreach ($a_attribs as $attribute => $value) {
1511 switch (strtolower($attribute)) {
1512 case "encoding":
1513 $this->render_type->setEncoding($value);
1514 break;
1515 case "fibtype":
1516 $this->render_type->setFibtype($value);
1517 break;
1518 case "rows":
1519 $this->render_type->setRows($value);
1520 break;
1521 case "maxchars":
1522 $this->render_type->setMaxchars($value);
1523 break;
1524 case "prompt":
1525 $this->render_type->setPrompt($value);
1526 break;
1527 case "columns":
1528 $this->render_type->setColumns($value);
1529 break;
1530 case "charset":
1531 $this->render_type->setCharset($value);
1532 break;
1533 case "maxnumber":
1534 $this->render_type->setMaxnumber($value);
1535 break;
1536 case "minnumber":
1537 $this->render_type->setMinnumber($value);
1538 break;
1539 }
1540 }
1541 }
1542
1543 private function renderHotspotBeginTag(array $a_attribs): void
1544 {
1545 if (!$this->in_response) {
1546 return;
1547 }
1548 $this->render_type = new ilQTIRenderHotspot();
1549 foreach ($a_attribs as $attribute => $value) {
1550 switch (strtolower($attribute)) {
1551 case "showdraw":
1552 $this->render_type->setShowdraw($value);
1553 break;
1554 case "minnumber":
1555 $this->render_type->setMinnumber($value);
1556 break;
1557 case "maxnumber":
1558 $this->render_type->setMaxnumber($value);
1559 break;
1560 }
1561 }
1562 }
1563
1564 private function renderChoiceBeginTag(array $a_attribs): void
1565 {
1566 if (!$this->in_response) {
1567 return;
1568 }
1569 $this->render_type = new ilQTIRenderChoice();
1570 foreach ($a_attribs as $attribute => $value) {
1571 switch (strtolower($attribute)) {
1572 case "shuffle":
1573 $this->render_type->setShuffle($value);
1574 break;
1575 case 'minnumber':
1576 $this->render_type->setMinnumber($value);
1577 break;
1578 case 'maxnumber':
1579 $this->render_type->setMaxnumber($value);
1580 break;
1581 }
1582 }
1583 }
1584
1585 private function responseLabelBeginTag(array $a_attribs): void
1586 {
1587 if ($this->render_type == null) {
1588 return;
1589 }
1590 $this->response_label = new ilQTIResponseLabel();
1591 foreach ($a_attribs as $attribute => $value) {
1592 switch (strtolower($attribute)) {
1593 case "rshuffle":
1594 $this->response_label->setRshuffle($value);
1595 break;
1596 case "rarea":
1597 $this->response_label->setRarea($value);
1598 break;
1599 case "rrange":
1600 $this->response_label->setRrange($value);
1601 break;
1602 case "labelrefid":
1603 $this->response_label->setLabelrefid($value);
1604 break;
1605 case "ident":
1606 $this->response_label->setIdent($value);
1607 break;
1608 case "match_group":
1609 $this->response_label->setMatchGroup($value);
1610 break;
1611 case "match_max":
1612 $this->response_label->setMatchMax($value);
1613 break;
1614 }
1615 }
1616 }
1617
1618 private function matAppletBeginTag(array $a_attribs): void
1619 {
1620 $this->matapplet = new ilQTIMatapplet();
1621 foreach ($a_attribs as $attribute => $value) {
1622 switch (strtolower($attribute)) {
1623 case "label":
1624 $this->matapplet->setLabel($value);
1625 break;
1626 case "uri":
1627 $this->matapplet->setUri($value);
1628 break;
1629 case "y0":
1630 $this->matapplet->setY0($value);
1631 break;
1632 case "height":
1633 $this->matapplet->setHeight($value);
1634 break;
1635 case "width":
1636 $this->matapplet->setWidth($value);
1637 break;
1638 case "x0":
1639 $this->matapplet->setX0($value);
1640 break;
1641 case "embedded":
1642 $this->matapplet->setEmbedded($value);
1643 break;
1644 case "entityref":
1645 $this->matapplet->setEntityref($value);
1646 break;
1647 }
1648 }
1649 }
1650
1651 private function matTextBeginTag(array $a_attribs): void
1652 {
1653 $this->mattext = new ilQTIMattext();
1654 foreach ($a_attribs as $attribute => $value) {
1655 switch (strtolower($attribute)) {
1656 case "texttype":
1657 $this->mattext->setTexttype($value);
1658 break;
1659 case "label":
1660 $this->mattext->setLabel($value);
1661 break;
1662 case "charset":
1663 $this->mattext->setCharset($value);
1664 break;
1665 case "uri":
1666 $this->mattext->setUri($value);
1667 break;
1668 case "xml:space":
1669 $this->mattext->setXmlspace($value);
1670 break;
1671 case "xml:lang":
1672 $this->mattext->setXmllang($value);
1673 break;
1674 case "entityref":
1675 $this->mattext->setEntityref($value);
1676 break;
1677 case "height":
1678 $this->mattext->setHeight($value);
1679 break;
1680 case "width":
1681 $this->mattext->setWidth($value);
1682 break;
1683 case "x0":
1684 $this->mattext->setX0($value);
1685 break;
1686 case "y0":
1687 $this->mattext->setY0($value);
1688 break;
1689 }
1690 }
1691 }
1692
1693 private function materialBeginTag(array $a_attribs): void
1694 {
1695 $this->material = new ilQTIMaterial();
1696 $this->material->setFlow($this->flow);
1697 foreach ($a_attribs as $attribute => $value) {
1698 switch (strtolower($attribute)) {
1699 case "label":
1700 $this->material->setLabel($value);
1701 break;
1702 }
1703 }
1704 }
1705
1706 private function matImageBeginTag(array $a_attribs): void
1707 {
1708 $this->matimage = new ilQTIMatimage();
1709 foreach ($a_attribs as $attribute => $value) {
1710 switch (strtolower($attribute)) {
1711 case "imagtype":
1712 $this->matimage->setImagetype($value);
1713 break;
1714 case "label":
1715 $this->matimage->setLabel($value);
1716 break;
1717 case "height":
1718 $this->matimage->setHeight($value);
1719 break;
1720 case "width":
1721 $this->matimage->setWidth($value);
1722 break;
1723 case "uri":
1724 $this->matimage->setUri($value);
1725 break;
1726 case "embedded":
1727 $this->matimage->setEmbedded($value);
1728 break;
1729 case "x0":
1730 $this->matimage->setX0($value);
1731 break;
1732 case "y0":
1733 $this->matimage->setY0($value);
1734 break;
1735 case "entityref":
1736 $this->matimage->setEntityref($value);
1737 break;
1738 }
1739 }
1740 if (!$this->matimage->getEmbedded() && strlen($this->matimage->getUri())) {
1741 $img_string = @file_get_contents(dirname($this->xml_file) . '/' . $this->matimage->getUri());
1742
1743 if (is_string($img_string)) {
1744 $this->matimage->setContent($img_string);
1745 }
1746 }
1747 }
1748
1749 private function decVarBeginTag(array $a_attribs): void
1750 {
1751 $this->decvar = new ilQTIDecvar();
1752 foreach ($a_attribs as $attribute => $value) {
1753 switch (strtolower($attribute)) {
1754 case "varname":
1755 $this->decvar->setVarname($value);
1756 break;
1757 case "vartype":
1758 $this->decvar->setVartype($value);
1759 break;
1760 case "defaultval":
1761 $this->decvar->setDefaultval($value);
1762 break;
1763 case "minvalue":
1764 $this->decvar->setMinvalue($value);
1765 break;
1766 case "maxvalue":
1767 $this->decvar->setMaxvalue($value);
1768 break;
1769 case "members":
1770 $this->decvar->setMembers($value);
1771 break;
1772 case "cutvalue":
1773 $this->decvar->setCutvalue($value);
1774 break;
1775 }
1776 }
1777 }
1778
1782 private function createParserStorage()
1783 {
1784 $parser = xml_parser_create();
1785 $is_resource = is_resource($parser);
1786 xml_parser_free($parser);
1787
1788 return $is_resource ? [] : new SplObjectStorage();
1789 }
1790}
static isImportable($questionTypeTag)
const QUESTION_SET_TYPE_RANDOM
const QUESTION_SET_TYPE_FIXED
const QT_MULTIPLE_CHOICE_MR
const QT_MULTIPLE_CHOICE_SR
const QT_NUMERIC
const QT_MATCHING
const QT_ORDERING
const QT_IMAGEMAP
resprocessingBeginTag(array $a_attribs)
setIgnoreItemsEnabled(bool $ignoreItemsEnabled)
renderChoiceBeginTag(array $a_attribs)
setHandlers($a_xml_parser)
set event handler should be overwritten by inherited class @access private
displayFeedbackBeginTag(array $a_attribs)
ilQTIConditionvar $conditionvar
ilObjTest $tst_object
fetchNumericVersionFromVersionDateString(string $versionDateString)
assessmentControlBeginTag(array $a_attribs)
itemBeginTag(array $a_attribs)
matTextBeginTag(array $a_attribs)
ilQTIRespcondition $respcondition
ilQTIPresentation $presentation
decVarBeginTag(array $a_attribs)
ilQTIObjectives $objectives
openXMLFile()
resource
handlerParseCharacterData($a_xml_parser, string $a_data)
ilQTIResponse $response
ilQTIDisplayfeedback $displayfeedback
ilQTISection $section
handlerParseBeginTag($a_xml_parser, string $a_name, array $a_attribs)
materialBeginTag(array $a_attribs)
virusDetected(string $buffer)
ilQTIResponseLabel $response_label
cleanInvalidXmlChars(string $xmlContent)
setQuestionSetType(string $questionSetType)
ilQTIResponseVar $responsevar
getParent($a_xml_parser)
ilQTIItemfeedback $itemfeedback
ilQTISetvar $setvar
matAppletBeginTag(array $a_attribs)
handlerCharacterData($a_xml_parser, string $a_data)
handlerVerifyCharacterData($a_xml_parser, string $a_data)
readonly int $user_id
string $verifyfieldentrytext
handlerVerifyBeginTag($a_xml_parser, string $a_name, array $a_attribs)
ilQTIDecvar $decvar
responseLabelBeginTag(array $a_attribs)
startParsing()
stores xml data in array
ilQTIPresentationMaterial $prensentation_material
matImageBeginTag(array $a_attribs)
itemFeedbackBeginTag(array $a_attribs)
ilQTIMaterial $material
setVarBeginTag(array $a_attribs)
ilQTIOutcomes $outcomes
string $verifyfieldlabeltext
bool $in_prensentation_material
getImportMapping()
Get array of new created questions for import id.
termsAndDefinitionsBeginTag(string $a_name, array $a_attribs)
setXMLContent(string $a_xml_content)
handlerVerifyEndTag($a_xml_parser, string $a_name)
ilQTIMattext $mattext
ilQTIResprocessing $resprocessing
renderFibBeginTag(array $a_attribs)
handlerParseEndTag($a_xml_parser, string $a_name)
@noinspection NotOptimalIfConditionsInspection
ilQTIAssessment $assessment
ilQTIMatimage $matimage
ilQTIAssessmentcontrol $assessmentcontrol
ilQTIMatapplet $matapplet
handlerBeginTag($a_xml_parser, string $a_name, array $a_attribs)
QuestionFiles $questionfiles
varEqualBeginTag(array $a_attribs)
fetchSourceNicFromItemIdent(string $itemIdent)
assessmentBeginTag(array $a_attribs)
setTestObject(ilObjTest $tst_object)
renderHotspotBeginTag(array $a_attribs)
handlerEndTag($a_xml_parser, string $a_name)
Class ilQTIPresentationMaterial.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct(?string $path_to_file='', ?bool $throw_exception=false)
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
QTI assessment class.
global $DIC
Definition: shib_login.php:26
$GLOBALS["DIC"]
Definition: wac.php:54