ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assClozeTestExport.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 "./Modules/TestQuestionPool/classes/export/qti12/class.assQuestionExport.php";
25 
36 {
46  function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
47  {
48  global $ilias;
49 
50  include_once "./Services/Math/classes/class.EvalMath.php";
51  $eval = new EvalMath();
52  $eval->suppress_errors = TRUE;
53  include_once("./Services/Xml/classes/class.ilXmlWriter.php");
54  $a_xml_writer = new ilXmlWriter;
55  // set xml header
56  $a_xml_writer->xmlHeader();
57  $a_xml_writer->xmlStartTag("questestinterop");
58  $attrs = array(
59  "ident" => "il_".IL_INST_ID."_qst_".$this->object->getId(),
60  "title" => $this->object->getTitle(),
61  "maxattempts" => $this->object->getNrOfTries()
62  );
63  $a_xml_writer->xmlStartTag("item", $attrs);
64  // add question description
65  $a_xml_writer->xmlElement("qticomment", NULL, $this->object->getComment());
66  // add estimated working time
67  $workingtime = $this->object->getEstimatedWorkingTime();
68  $duration = sprintf("P0Y0M0DT%dH%dM%dS", $workingtime["h"], $workingtime["m"], $workingtime["s"]);
69  $a_xml_writer->xmlElement("duration", NULL, $duration);
70  // add ILIAS specific metadata
71  $a_xml_writer->xmlStartTag("itemmetadata");
72  $a_xml_writer->xmlStartTag("qtimetadata");
73  $a_xml_writer->xmlStartTag("qtimetadatafield");
74  $a_xml_writer->xmlElement("fieldlabel", NULL, "ILIAS_VERSION");
75  $a_xml_writer->xmlElement("fieldentry", NULL, $ilias->getSetting("ilias_version"));
76  $a_xml_writer->xmlEndTag("qtimetadatafield");
77  $a_xml_writer->xmlStartTag("qtimetadatafield");
78  $a_xml_writer->xmlElement("fieldlabel", NULL, "QUESTIONTYPE");
79  $a_xml_writer->xmlElement("fieldentry", NULL, CLOZE_TEST_IDENTIFIER);
80  $a_xml_writer->xmlEndTag("qtimetadatafield");
81  $a_xml_writer->xmlStartTag("qtimetadatafield");
82  $a_xml_writer->xmlElement("fieldlabel", NULL, "AUTHOR");
83  $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getAuthor());
84  $a_xml_writer->xmlEndTag("qtimetadatafield");
85  $a_xml_writer->xmlStartTag("qtimetadatafield");
86  $a_xml_writer->xmlElement("fieldlabel", NULL, "textgaprating");
87  $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getTextgapRating());
88  $a_xml_writer->xmlEndTag("qtimetadatafield");
89  $a_xml_writer->xmlStartTag("qtimetadatafield");
90  $a_xml_writer->xmlElement("fieldlabel", NULL, "fixedTextLength");
91  $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getFixedTextLength());
92  $a_xml_writer->xmlEndTag("qtimetadatafield");
93  $a_xml_writer->xmlStartTag("qtimetadatafield");
94  $a_xml_writer->xmlElement("fieldlabel", NULL, "identicalScoring");
95  $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getIdenticalScoring());
96  $a_xml_writer->xmlEndTag("qtimetadatafield");
97  $a_xml_writer->xmlStartTag("qtimetadatafield");
98  $a_xml_writer->xmlElement("fieldlabel", NULL, "externalID");
99  $a_xml_writer->xmlElement("fieldentry", NULL, $this->object->getExternalID());
100  $a_xml_writer->xmlEndTag("qtimetadatafield");
101  $a_xml_writer->xmlEndTag("qtimetadata");
102  $a_xml_writer->xmlEndTag("itemmetadata");
103 
104  // PART I: qti presentation
105  $attrs = array(
106  "label" => $this->object->getTitle()
107  );
108  $a_xml_writer->xmlStartTag("presentation", $attrs);
109  // add flow to presentation
110  $a_xml_writer->xmlStartTag("flow");
111  $text_parts = preg_split("/\[gap.*?\[\/gap\]/", $this->object->getClozeText());
112  // add material with question text to presentation
113  for ($i = 0; $i <= $this->object->getGapCount(); $i++)
114  {
115  // n-th text part
116  if ($i == 0)
117  {
118  $this->object->addQTIMaterial($a_xml_writer, $text_parts[$i]);
119  }
120  else
121  {
122  $this->object->addQTIMaterial($a_xml_writer, $text_parts[$i], TRUE, FALSE);
123  }
124 
125  if ($i < $this->object->getGapCount())
126  {
127  // add gap
128  $gap = $this->object->getGap($i);
129  switch ($gap->getType())
130  {
131  case CLOZE_SELECT:
132  // comboboxes
133  $attrs = array(
134  "ident" => "gap_$i",
135  "rcardinality" => "Single"
136  );
137  $a_xml_writer->xmlStartTag("response_str", $attrs);
138  $solution = $this->object->getSuggestedSolution($i);
139  if (count($solution))
140  {
141  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
142  {
143  $attrs = array(
144  "label" => "suggested_solution"
145  );
146  $a_xml_writer->xmlStartTag("material", $attrs);
147  $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
148  if (strcmp($matches[1], "") != 0)
149  {
150  $intlink = $solution["internal_link"];
151  }
152  $a_xml_writer->xmlElement("mattext", NULL, $intlink);
153  $a_xml_writer->xmlEndTag("material");
154  }
155  }
156 
157  $attrs = array("shuffle" => ($gap->getShuffle() ? "Yes" : "No"));
158  $a_xml_writer->xmlStartTag("render_choice", $attrs);
159 
160  // add answers
161  foreach ($gap->getItems() as $answeritem)
162  {
163  $attrs = array(
164  "ident" => $answeritem->getOrder()
165  );
166  $a_xml_writer->xmlStartTag("response_label", $attrs);
167  $a_xml_writer->xmlStartTag("material");
168  $a_xml_writer->xmlElement("mattext", NULL, $answeritem->getAnswertext());
169  $a_xml_writer->xmlEndTag("material");
170  $a_xml_writer->xmlEndTag("response_label");
171  }
172  $a_xml_writer->xmlEndTag("render_choice");
173  $a_xml_writer->xmlEndTag("response_str");
174  break;
175  case CLOZE_TEXT:
176  // text fields
177  $attrs = array(
178  "ident" => "gap_$i",
179  "rcardinality" => "Single"
180  );
181  $a_xml_writer->xmlStartTag("response_str", $attrs);
182  $solution = $this->object->getSuggestedSolution($i);
183  if (count($solution))
184  {
185  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
186  {
187  $attrs = array(
188  "label" => "suggested_solution"
189  );
190  $a_xml_writer->xmlStartTag("material", $attrs);
191  $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
192  if (strcmp($matches[1], "") != 0)
193  {
194  $intlink = $solution["internal_link"];
195  }
196  $a_xml_writer->xmlElement("mattext", NULL, $intlink);
197  $a_xml_writer->xmlEndTag("material");
198  }
199  }
200  $attrs = array(
201  "fibtype" => "String",
202  "prompt" => "Box",
203  "columns" => $gap->getMaxWidth()
204  );
205  $a_xml_writer->xmlStartTag("render_fib", $attrs);
206  $a_xml_writer->xmlEndTag("render_fib");
207  $a_xml_writer->xmlEndTag("response_str");
208  break;
209  case CLOZE_NUMERIC:
210  // numeric fields
211  $attrs = array(
212  "ident" => "gap_$i",
213  "numtype" => "Decimal",
214  "rcardinality" => "Single"
215  );
216  $a_xml_writer->xmlStartTag("response_num", $attrs);
217  $solution = $this->object->getSuggestedSolution($i);
218  if (count($solution))
219  {
220  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
221  {
222  $attrs = array(
223  "label" => "suggested_solution"
224  );
225  $a_xml_writer->xmlStartTag("material", $attrs);
226  $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
227  if (strcmp($matches[1], "") != 0)
228  {
229  $intlink = $solution["internal_link"];
230  }
231  $a_xml_writer->xmlElement("mattext", NULL, $intlink);
232  $a_xml_writer->xmlEndTag("material");
233  }
234  }
235  $answeritem = $gap->getItem(0);
236  $attrs = array(
237  "fibtype" => "Decimal",
238  "prompt" => "Box",
239  "columns" => $gap->getMaxWidth()
240  );
241  if (is_object($answeritem))
242  {
243  if ($eval->e($answeritem->getLowerBound()) !== FALSE)
244  {
245  $attrs["minnumber"] = $answeritem->getLowerBound();
246  }
247  if ($eval->e($answeritem->getUpperBound()) !== FALSE)
248  {
249  $attrs["maxnumber"] = $answeritem->getUpperBound();
250  }
251  }
252  $a_xml_writer->xmlStartTag("render_fib", $attrs);
253  $a_xml_writer->xmlEndTag("render_fib");
254  $a_xml_writer->xmlEndTag("response_num");
255  break;
256  }
257  }
258  }
259  $a_xml_writer->xmlEndTag("flow");
260  $a_xml_writer->xmlEndTag("presentation");
261 
262  // PART II: qti resprocessing
263  $a_xml_writer->xmlStartTag("resprocessing");
264  $a_xml_writer->xmlStartTag("outcomes");
265  $a_xml_writer->xmlStartTag("decvar");
266  $a_xml_writer->xmlEndTag("decvar");
267  $a_xml_writer->xmlEndTag("outcomes");
268 
269  // add response conditions
270  for ($i = 0; $i < $this->object->getGapCount(); $i++)
271  {
272  $gap = $this->object->getGap($i);
273  switch ($gap->getType())
274  {
275  case CLOZE_SELECT:
276  foreach ($gap->getItems() as $answer)
277  {
278  $attrs = array(
279  "continue" => "Yes"
280  );
281  $a_xml_writer->xmlStartTag("respcondition", $attrs);
282  // qti conditionvar
283  $a_xml_writer->xmlStartTag("conditionvar");
284 
285  $attrs = array(
286  "respident" => "gap_$i"
287  );
288  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
289  $a_xml_writer->xmlEndTag("conditionvar");
290  // qti setvar
291  $attrs = array(
292  "action" => "Add"
293  );
294  $a_xml_writer->xmlElement("setvar", $attrs, $answer->getPoints());
295  // qti displayfeedback
296  $linkrefid = "";
297  $linkrefid = "$i" . "_Response_" . $answer->getOrder();
298  $attrs = array(
299  "feedbacktype" => "Response",
300  "linkrefid" => $linkrefid
301  );
302  $a_xml_writer->xmlElement("displayfeedback", $attrs);
303  $a_xml_writer->xmlEndTag("respcondition");
304  }
305  break;
306  case CLOZE_TEXT:
307  foreach ($gap->getItems() as $answer)
308  {
309  $attrs = array(
310  "continue" => "Yes"
311  );
312  $a_xml_writer->xmlStartTag("respcondition", $attrs);
313  // qti conditionvar
314  $a_xml_writer->xmlStartTag("conditionvar");
315  $attrs = array(
316  "respident" => "gap_$i"
317  );
318  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
319  $a_xml_writer->xmlEndTag("conditionvar");
320  // qti setvar
321  $attrs = array(
322  "action" => "Add"
323  );
324  $a_xml_writer->xmlElement("setvar", $attrs, $answer->getPoints());
325  // qti displayfeedback
326  $linkrefid = "$i" . "_Response_" . $answer->getOrder();
327  $attrs = array(
328  "feedbacktype" => "Response",
329  "linkrefid" => $linkrefid
330  );
331  $a_xml_writer->xmlElement("displayfeedback", $attrs);
332  $a_xml_writer->xmlEndTag("respcondition");
333  }
334  break;
335  case CLOZE_NUMERIC:
336  foreach ($gap->getItems() as $answer)
337  {
338  $attrs = array(
339  "continue" => "Yes"
340  );
341  $a_xml_writer->xmlStartTag("respcondition", $attrs);
342  // qti conditionvar
343  $a_xml_writer->xmlStartTag("conditionvar");
344  $attrs = array(
345  "respident" => "gap_$i"
346  );
347  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
348  $a_xml_writer->xmlEndTag("conditionvar");
349  // qti setvar
350  $attrs = array(
351  "action" => "Add"
352  );
353  $a_xml_writer->xmlElement("setvar", $attrs, $answer->getPoints());
354  // qti displayfeedback
355  $linkrefid = "$i" . "_Response_" . $answer->getOrder();
356  $attrs = array(
357  "feedbacktype" => "Response",
358  "linkrefid" => $linkrefid
359  );
360  $a_xml_writer->xmlElement("displayfeedback", $attrs);
361  $a_xml_writer->xmlEndTag("respcondition");
362  }
363  break;
364  }
365  }
366 
367  $feedback_allcorrect = $this->object->getFeedbackGeneric(1);
368  if (strlen($feedback_allcorrect))
369  {
370  $attrs = array(
371  "continue" => "Yes"
372  );
373  $a_xml_writer->xmlStartTag("respcondition", $attrs);
374  // qti conditionvar
375  $a_xml_writer->xmlStartTag("conditionvar");
376 
377  for ($i = 0; $i < $this->object->getGapCount(); $i++)
378  {
379  $gap = $this->object->getGap($i);
380  $indexes = $gap->getBestSolutionIndexes();
381  if ($i > 0)
382  {
383  $a_xml_writer->xmlStartTag("and");
384  }
385  switch ($gap->getType())
386  {
387  case CLOZE_SELECT:
388  $k = 0;
389  foreach ($indexes as $key)
390  {
391  if ($k > 0)
392  {
393  $a_xml_writer->xmlStartTag("or");
394  }
395  $attrs = array(
396  "respident" => "gap_$i"
397  );
398  $answer = $gap->getItem($key);
399  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
400  if ($k > 0)
401  {
402  $a_xml_writer->xmlEndTag("or");
403  }
404  $k++;
405  }
406  break;
407  case CLOZE_TEXT:
408  $k = 0;
409  foreach ($indexes as $key)
410  {
411  if ($k > 0)
412  {
413  $a_xml_writer->xmlStartTag("or");
414  }
415  $attrs = array(
416  "respident" => "gap_$i"
417  );
418  $answer = $gap->getItem($key);
419  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
420  if ($k > 0)
421  {
422  $a_xml_writer->xmlEndTag("or");
423  }
424  $k++;
425  }
426  break;
427  case CLOZE_NUMERIC:
428  $k = 0;
429  foreach ($indexes as $key)
430  {
431  if ($k > 0)
432  {
433  $a_xml_writer->xmlStartTag("or");
434  }
435  $attrs = array(
436  "respident" => "gap_$i"
437  );
438  $answer = $gap->getItem($key);
439  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
440  if ($k > 0)
441  {
442  $a_xml_writer->xmlEndTag("or");
443  }
444  $k++;
445  }
446  break;
447  }
448  if ($i > 0)
449  {
450  $a_xml_writer->xmlEndTag("and");
451  }
452  }
453  $a_xml_writer->xmlEndTag("conditionvar");
454  // qti displayfeedback
455  $attrs = array(
456  "feedbacktype" => "Response",
457  "linkrefid" => "response_allcorrect"
458  );
459  $a_xml_writer->xmlElement("displayfeedback", $attrs);
460  $a_xml_writer->xmlEndTag("respcondition");
461  }
462  $feedback_onenotcorrect = $this->object->getFeedbackGeneric(0);
463  if (strlen($feedback_onenotcorrect))
464  {
465  $attrs = array(
466  "continue" => "Yes"
467  );
468  $a_xml_writer->xmlStartTag("respcondition", $attrs);
469  // qti conditionvar
470  $a_xml_writer->xmlStartTag("conditionvar");
471 
472  $a_xml_writer->xmlStartTag("not");
473  for ($i = 0; $i < $this->object->getGapCount(); $i++)
474  {
475  $gap = $this->object->getGap($i);
476  $indexes = $gap->getBestSolutionIndexes();
477  if ($i > 0)
478  {
479  $a_xml_writer->xmlStartTag("and");
480  }
481  switch ($gap->getType())
482  {
483  case CLOZE_SELECT:
484  $k = 0;
485  foreach ($indexes as $key)
486  {
487  if ($k > 0)
488  {
489  $a_xml_writer->xmlStartTag("or");
490  }
491  $attrs = array(
492  "respident" => "gap_$i"
493  );
494  $answer = $gap->getItem($key);
495  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
496  if ($k > 0)
497  {
498  $a_xml_writer->xmlEndTag("or");
499  }
500  $k++;
501  }
502  break;
503  case CLOZE_TEXT:
504  $k = 0;
505  foreach ($indexes as $key)
506  {
507  if ($k > 0)
508  {
509  $a_xml_writer->xmlStartTag("or");
510  }
511  $attrs = array(
512  "respident" => "gap_$i"
513  );
514  $answer = $gap->getItem($key);
515  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
516  if ($k > 0)
517  {
518  $a_xml_writer->xmlEndTag("or");
519  }
520  $k++;
521  }
522  break;
523  case CLOZE_NUMERIC:
524  $k = 0;
525  foreach ($indexes as $key)
526  {
527  if ($k > 0)
528  {
529  $a_xml_writer->xmlStartTag("or");
530  }
531  $attrs = array(
532  "respident" => "gap_$i"
533  );
534  $answer = $gap->getItem($key);
535  $a_xml_writer->xmlElement("varequal", $attrs, $answer->getAnswertext());
536  if ($k > 0)
537  {
538  $a_xml_writer->xmlEndTag("or");
539  }
540  $k++;
541  }
542  break;
543  }
544  if ($i > 0)
545  {
546  $a_xml_writer->xmlEndTag("and");
547  }
548  }
549  $a_xml_writer->xmlEndTag("not");
550  $a_xml_writer->xmlEndTag("conditionvar");
551  // qti displayfeedback
552  $attrs = array(
553  "feedbacktype" => "Response",
554  "linkrefid" => "response_onenotcorrect"
555  );
556  $a_xml_writer->xmlElement("displayfeedback", $attrs);
557  $a_xml_writer->xmlEndTag("respcondition");
558  }
559 
560  $a_xml_writer->xmlEndTag("resprocessing");
561 
562  // PART III: qti itemfeedback
563  for ($i = 0; $i < $this->object->getGapCount(); $i++)
564  {
565  $gap = $this->object->getGap($i);
566  switch ($gap->getType())
567  {
568  case CLOZE_SELECT:
569  foreach ($gap->getItems() as $answer)
570  {
571  $linkrefid = "$i" . "_Response_" . $answer->getOrder();
572  $attrs = array(
573  "ident" => $linkrefid,
574  "view" => "All"
575  );
576  $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
577  // qti flow_mat
578  $a_xml_writer->xmlStartTag("flow_mat");
579  $a_xml_writer->xmlStartTag("material");
580  $a_xml_writer->xmlElement("mattext");
581  $a_xml_writer->xmlEndTag("material");
582  $a_xml_writer->xmlEndTag("flow_mat");
583  $a_xml_writer->xmlEndTag("itemfeedback");
584  }
585  break;
586  case CLOZE_TEXT:
587  foreach ($gap->getItems() as $answer)
588  {
589  $linkrefid = "$i" . "_Response_" . $answer->getOrder();
590  $attrs = array(
591  "ident" => $linkrefid,
592  "view" => "All"
593  );
594  $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
595  // qti flow_mat
596  $a_xml_writer->xmlStartTag("flow_mat");
597  $a_xml_writer->xmlStartTag("material");
598  $a_xml_writer->xmlElement("mattext");
599  $a_xml_writer->xmlEndTag("material");
600  $a_xml_writer->xmlEndTag("flow_mat");
601  $a_xml_writer->xmlEndTag("itemfeedback");
602  }
603  break;
604  case CLOZE_NUMERIC:
605  foreach ($gap->getItems() as $answer)
606  {
607  $linkrefid = "$i" . "_Response_" . $answer->getOrder();
608  $attrs = array(
609  "ident" => $linkrefid,
610  "view" => "All"
611  );
612  $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
613  // qti flow_mat
614  $a_xml_writer->xmlStartTag("flow_mat");
615  $a_xml_writer->xmlStartTag("material");
616  $a_xml_writer->xmlElement("mattext");
617  $a_xml_writer->xmlEndTag("material");
618  $a_xml_writer->xmlEndTag("flow_mat");
619  $a_xml_writer->xmlEndTag("itemfeedback");
620  }
621  break;
622  }
623  }
624 
625  if (strlen($feedback_allcorrect))
626  {
627  $attrs = array(
628  "ident" => "response_allcorrect",
629  "view" => "All"
630  );
631  $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
632  // qti flow_mat
633  $a_xml_writer->xmlStartTag("flow_mat");
634  $this->object->addQTIMaterial($a_xml_writer, $feedback_allcorrect);
635  $a_xml_writer->xmlEndTag("flow_mat");
636  $a_xml_writer->xmlEndTag("itemfeedback");
637  }
638  if (strlen($feedback_onenotcorrect))
639  {
640  $attrs = array(
641  "ident" => "response_onenotcorrect",
642  "view" => "All"
643  );
644  $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
645  // qti flow_mat
646  $a_xml_writer->xmlStartTag("flow_mat");
647  $this->object->addQTIMaterial($a_xml_writer, $feedback_onenotcorrect);
648  $a_xml_writer->xmlEndTag("flow_mat");
649  $a_xml_writer->xmlEndTag("itemfeedback");
650  }
651 
652  $a_xml_writer->xmlEndTag("item");
653  $a_xml_writer->xmlEndTag("questestinterop");
654 
655  $xml = $a_xml_writer->xmlDumpMem(FALSE);
656  if (!$a_include_header)
657  {
658  $pos = strpos($xml, "?>");
659  $xml = substr($xml, $pos + 2);
660  }
661  return $xml;
662  }
663 }
664 
665 ?>