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