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