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