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