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