|
@@ -66,7 +66,7 @@ function get_and_unzip_uploaded_exercise($baseWorkDir, $uploadPath)
|
|
|
|
|
|
* Imports an exercise in QTI format if the XML structure can be found in it
|
|
|
* @param array $file
|
|
|
- * @return an array as a backlog of what was really imported, and error or debug messages to display
|
|
|
+ * @return string|array as a backlog of what was really imported, and error or debug messages to display
|
|
|
*/
|
|
|
function import_exercise($file)
|
|
|
{
|
|
@@ -165,19 +165,30 @@ function import_exercise($file)
|
|
|
$question = new Ims2Question();
|
|
|
$question->type = $question_array['type'];
|
|
|
$question->setAnswer();
|
|
|
- $question->updateTitle(formatText($question_array['title']));
|
|
|
+ if (strlen($question_array['title']) < 50) {
|
|
|
+ $question->updateTitle(formatText(strip_tags($question_array['title'])) . '...');
|
|
|
+ } else {
|
|
|
+ $question->updateTitle(formatText(substr(strip_tags($question_array['title']), 0, 50)));
|
|
|
+ $question->updateDescription($question_array['title']);
|
|
|
+ }
|
|
|
|
|
|
- $type = $question->selectType();
|
|
|
- $question->type = constant($type);
|
|
|
$question->save($last_exercise_id);
|
|
|
$last_question_id = $question->selectId();
|
|
|
|
|
|
$answer = new Answer($last_question_id);
|
|
|
$answer->new_nbrAnswers = count($question_array['answer']);
|
|
|
$totalCorrectWeight = 0;
|
|
|
+ $j = 1;
|
|
|
+ $matchAnswerIds = array();
|
|
|
foreach ($question_array['answer'] as $key => $answers) {
|
|
|
- $split = explode('_', $key);
|
|
|
- $i = $split[1];
|
|
|
+ if (preg_match('/_/', $key)) {
|
|
|
+ $split = explode('_', $key);
|
|
|
+ $i = $split[1];
|
|
|
+ } else {
|
|
|
+ $i = $j;
|
|
|
+ $j++;
|
|
|
+ $matchAnswerIds[$key] = $j;
|
|
|
+ }
|
|
|
|
|
|
$answer->new_answer[$i] = formatText($answers['value']);
|
|
|
|
|
@@ -192,7 +203,7 @@ function import_exercise($file)
|
|
|
}
|
|
|
$answer->new_weighting[$i] = $question_array['weighting'][$key];
|
|
|
if ($answer->new_correct[$i]) {
|
|
|
- $totalCorrectWeight = $answer->new_weighting[$i];
|
|
|
+ $totalCorrectWeight += $answer->new_weighting[$i];
|
|
|
}
|
|
|
}
|
|
|
$question->updateWeighting($totalCorrectWeight);
|
|
@@ -242,6 +253,12 @@ function parse_file($exercisePath, $file, $questionFile)
|
|
|
|
|
|
|
|
|
$data = str_replace(array('<p>', '</p>', '<front>', '</front>'), '', $data);
|
|
|
+ $qtiVersion = array();
|
|
|
+ $match = preg_match('/ims_qtiasiv(\d)p(\d)/', $data, $qtiVersion);
|
|
|
+ $qtiMainVersion = 2;
|
|
|
+ if ($match) {
|
|
|
+ $qtiMainVersion = $qtiVersion[1];
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
@@ -265,8 +282,13 @@ function parse_file($exercisePath, $file, $questionFile)
|
|
|
|
|
|
$xml_parser = xml_parser_create();
|
|
|
xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, false);
|
|
|
- xml_set_element_handler($xml_parser, 'startElement', 'endElement');
|
|
|
- xml_set_character_data_handler($xml_parser, 'elementData');
|
|
|
+ if ($qtiMainVersion == 1) {
|
|
|
+ xml_set_element_handler($xml_parser, 'startElementQti1', 'endElementQti1');
|
|
|
+ xml_set_character_data_handler($xml_parser, 'elementDataQti1');
|
|
|
+ } else {
|
|
|
+ xml_set_element_handler($xml_parser, 'startElementQti2', 'endElementQti2');
|
|
|
+ xml_set_character_data_handler($xml_parser, 'elementDataQti2');
|
|
|
+ }
|
|
|
if (!xml_parse($xml_parser, $data, feof($fp))) {
|
|
|
|
|
|
|
|
@@ -300,7 +322,7 @@ function parse_file($exercisePath, $file, $questionFile)
|
|
|
* @param string $name name of the element
|
|
|
* @param array $attributes
|
|
|
*/
|
|
|
-function startElement($parser, $name, $attributes)
|
|
|
+function startElementQti2($parser, $name, $attributes)
|
|
|
{
|
|
|
global $element_pile;
|
|
|
global $exercise_info;
|
|
@@ -341,7 +363,6 @@ function startElement($parser, $name, $attributes)
|
|
|
|
|
|
|
|
|
if ($current_element == 'INLINECHOICEINTERACTION') {
|
|
|
-
|
|
|
$current_question_item_body .= "**claroline_start**" . $attributes['RESPONSEIDENTIFIER'] . "**claroline_end**";
|
|
|
}
|
|
|
if ($current_element == 'TEXTENTRYINTERACTION') {
|
|
@@ -354,6 +375,7 @@ function startElement($parser, $name, $attributes)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
switch ($current_element) {
|
|
|
case 'ASSESSMENTITEM':
|
|
|
|
|
@@ -373,18 +395,18 @@ function startElement($parser, $name, $attributes)
|
|
|
case 'RESPONSEDECLARATION':
|
|
|
|
|
|
if ("multiple" == $attributes['CARDINALITY']) {
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = 'MCMA';
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MCMA;
|
|
|
$cardinality = 'multiple';
|
|
|
}
|
|
|
if ("single" == $attributes['CARDINALITY']) {
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = 'MCUA';
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
$cardinality = 'single';
|
|
|
}
|
|
|
|
|
|
$current_answer_id = $attributes['IDENTIFIER'];
|
|
|
break;
|
|
|
case 'INLINECHOICEINTERACTION':
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = 'FIB';
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = FIB;
|
|
|
$exercise_info['question'][$current_question_ident]['subtype'] = 'LISTBOX_FILL';
|
|
|
$current_answer_id = $attributes['RESPONSEIDENTIFIER'];
|
|
|
break;
|
|
@@ -392,13 +414,13 @@ function startElement($parser, $name, $attributes)
|
|
|
$current_inlinechoice_id = $attributes['IDENTIFIER'];
|
|
|
break;
|
|
|
case 'TEXTENTRYINTERACTION':
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = 'FIB';
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = FIB;
|
|
|
$exercise_info['question'][$current_question_ident]['subtype'] = 'TEXTFIELD_FILL';
|
|
|
$exercise_info['question'][$current_question_ident]['response_text'] = $current_question_item_body;
|
|
|
|
|
|
break;
|
|
|
case 'MATCHINTERACTION':
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = 'MATCHING';
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MATCHING;
|
|
|
break;
|
|
|
case 'SIMPLEMATCHSET':
|
|
|
if (!isset($current_match_set)) {
|
|
@@ -447,7 +469,7 @@ function startElement($parser, $name, $attributes)
|
|
|
* @param $parser xml parser created with "xml_parser_create()"
|
|
|
* @param $name name of the element
|
|
|
*/
|
|
|
-function endElement($parser, $name)
|
|
|
+function endElementQti2($parser, $name)
|
|
|
{
|
|
|
global $element_pile;
|
|
|
global $exercise_info;
|
|
@@ -468,7 +490,7 @@ function endElement($parser, $name)
|
|
|
switch ($name) {
|
|
|
case 'ITEMBODY':
|
|
|
$record_item_body = false;
|
|
|
- if ($exercise_info['question'][$current_question_ident]['type'] == 'FIB') {
|
|
|
+ if ($exercise_info['question'][$current_question_ident]['type'] == FIB) {
|
|
|
$exercise_info['question'][$current_question_ident]['response_text'] = $current_question_item_body;
|
|
|
} else {
|
|
|
$exercise_info['question'][$current_question_ident]['statement'] = $current_question_item_body;
|
|
@@ -482,7 +504,7 @@ function endElement($parser, $name)
|
|
|
* @param $parser
|
|
|
* @param $data
|
|
|
*/
|
|
|
-function elementData($parser, $data)
|
|
|
+function elementDataQti2($parser, $data)
|
|
|
{
|
|
|
global $element_pile;
|
|
|
global $exercise_info;
|
|
@@ -562,3 +584,319 @@ function elementData($parser, $data)
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ * Function used by the SAX xml parser when the parser meets a opening tag for QTI1
|
|
|
+ *
|
|
|
+ * @param object $parser xml parser created with "xml_parser_create()"
|
|
|
+ * @param string $name name of the element
|
|
|
+ * @param array $attributes
|
|
|
+ */
|
|
|
+function startElementQti1($parser, $name, $attributes)
|
|
|
+{
|
|
|
+ global $element_pile;
|
|
|
+ global $exercise_info;
|
|
|
+ global $current_question_ident;
|
|
|
+ global $current_answer_id;
|
|
|
+ global $current_match_set;
|
|
|
+ global $currentAssociableChoice;
|
|
|
+ global $current_question_item_body;
|
|
|
+ global $record_item_body;
|
|
|
+ global $non_HTML_tag_to_avoid;
|
|
|
+ global $current_inlinechoice_id;
|
|
|
+ global $cardinality;
|
|
|
+ global $questionTempDir;
|
|
|
+ global $lastLabelFieldName;
|
|
|
+ global $lastLabelFieldValue;
|
|
|
+
|
|
|
+ array_push($element_pile, $name);
|
|
|
+ $current_element = end($element_pile);
|
|
|
+ if (sizeof($element_pile) >= 2) {
|
|
|
+ $parent_element = $element_pile[sizeof($element_pile) - 2];
|
|
|
+ } else {
|
|
|
+ $parent_element = "";
|
|
|
+ }
|
|
|
+ if (sizeof($element_pile) >= 3) {
|
|
|
+ $grand_parent_element = $element_pile[sizeof($element_pile) - 3];
|
|
|
+ } else {
|
|
|
+ $grand_parent_element = "";
|
|
|
+ }
|
|
|
+ if (sizeof($element_pile) >= 4) {
|
|
|
+ $great_grand_parent_element = $element_pile[sizeof($element_pile) - 4];
|
|
|
+ } else {
|
|
|
+ $great_grand_parent_element = "";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if ($record_item_body) {
|
|
|
+
|
|
|
+ if ((!in_array($current_element, $non_HTML_tag_to_avoid))) {
|
|
|
+ $current_question_item_body .= "<" . $name;
|
|
|
+ foreach ($attributes as $attribute_name => $attribute_value) {
|
|
|
+ $current_question_item_body .= " " . $attribute_name . "=\"" . $attribute_value . "\"";
|
|
|
+ }
|
|
|
+ $current_question_item_body .= ">";
|
|
|
+ } else {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if ($current_element == 'INLINECHOICEINTERACTION') {
|
|
|
+ $current_question_item_body .= "**claroline_start**" . $attributes['RESPONSEIDENTIFIER'] . "**claroline_end**";
|
|
|
+ }
|
|
|
+ if ($current_element == 'TEXTENTRYINTERACTION') {
|
|
|
+ $correct_answer_value = $exercise_info['question'][$current_question_ident]['correct_answers'][$current_answer_id];
|
|
|
+ $current_question_item_body .= "[" . $correct_answer_value . "]";
|
|
|
+
|
|
|
+ }
|
|
|
+ if ($current_element == 'BR') {
|
|
|
+ $current_question_item_body .= "<br />";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ switch ($current_element) {
|
|
|
+ case 'ASSESSMENT':
|
|
|
+
|
|
|
+ if (!empty($attributes['TITLE'])) {
|
|
|
+ $exercise_info['name'] = $attributes['TITLE'];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'ITEM':
|
|
|
+
|
|
|
+ $current_question_ident = $attributes['IDENT'];
|
|
|
+ $exercise_info['question'][$current_question_ident] = array();
|
|
|
+ $exercise_info['question'][$current_question_ident]['answer'] = array();
|
|
|
+ $exercise_info['question'][$current_question_ident]['correct_answers'] = array();
|
|
|
+
|
|
|
+ $exercise_info['question'][$current_question_ident]['tempdir'] = $questionTempDir;
|
|
|
+ break;
|
|
|
+ case 'SECTION':
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ break;
|
|
|
+ case 'RESPONSE_LID':
|
|
|
+
|
|
|
+ if ("multiple" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
+ $cardinality = 'multiple';
|
|
|
+ }
|
|
|
+ if ("single" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
+ $cardinality = 'single';
|
|
|
+ }
|
|
|
+
|
|
|
+ $current_answer_id = $attributes['IDENT'];
|
|
|
+ $current_question_item_body = '';
|
|
|
+ break;
|
|
|
+ case 'RENDER_CHOICE';
|
|
|
+ break;
|
|
|
+ case 'RESPONSE_LABEL':
|
|
|
+ if (!empty($attributes['IDENT'])) {
|
|
|
+ $current_answer_id = $attributes['IDENT'];
|
|
|
+
|
|
|
+ $exercise_info['question'][$current_question_ident]['answer'][$current_answer_id] = '';
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'DECVAR':
|
|
|
+ if ($parent_element == 'OUTCOMES' && $grand_parent_element == 'RESPROCESSING') {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'VAREQUAL':
|
|
|
+ if ($parent_element == 'CONDITIONVAR' && $grand_parent_element == 'RESPCONDITION') {
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'SETVAR':
|
|
|
+ if ($parent_element == 'RESPCONDITION') {
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'IMG':
|
|
|
+
|
|
|
+ break;
|
|
|
+ case 'MATTEXT':
|
|
|
+ if ($parent_element == 'MATERIAL') {
|
|
|
+ if ($grand_parent_element == 'PRESENTATION') {
|
|
|
+ $exercise_info['question'][$current_question_ident]['title'] = $current_question_item_body;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * Function used by the SAX xml parser when the parser meets a closing tag for QTI1
|
|
|
+ *
|
|
|
+ * @param object $parser xml parser created with "xml_parser_create()"
|
|
|
+ * @param string $name name of the element
|
|
|
+ * @param array $attributes The element attributes
|
|
|
+ */
|
|
|
+function endElementQti1($parser, $name, $attributes)
|
|
|
+{
|
|
|
+ global $element_pile;
|
|
|
+ global $exercise_info;
|
|
|
+ global $current_question_ident;
|
|
|
+ global $record_item_body;
|
|
|
+ global $current_question_item_body;
|
|
|
+ global $non_HTML_tag_to_avoid;
|
|
|
+ global $cardinality;
|
|
|
+ global $lastLabelFieldName;
|
|
|
+ global $lastLabelFieldValue;
|
|
|
+
|
|
|
+ $current_element = end($element_pile);
|
|
|
+ if (sizeof($element_pile) >= 2) {
|
|
|
+ $parent_element = $element_pile[sizeof($element_pile) - 2];
|
|
|
+ } else {
|
|
|
+ $parent_element = "";
|
|
|
+ }
|
|
|
+ if (sizeof($element_pile) >= 3) {
|
|
|
+ $grand_parent_element = $element_pile[sizeof($element_pile) - 3];
|
|
|
+ } else {
|
|
|
+ $grand_parent_element = "";
|
|
|
+ }
|
|
|
+ if (sizeof($element_pile) >= 4) {
|
|
|
+ $great_grand_parent_element = $element_pile[sizeof($element_pile) - 4];
|
|
|
+ } else {
|
|
|
+ $great_grand_parent_element = "";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
|
|
|
+ $current_question_item_body .= "</" . $name . ">";
|
|
|
+ }
|
|
|
+
|
|
|
+ switch ($name) {
|
|
|
+ case 'MATTEXT':
|
|
|
+ if ($parent_element == 'MATERIAL') {
|
|
|
+ if ($grand_parent_element == 'PRESENTATION') {
|
|
|
+ $exercise_info['question'][$current_question_ident]['title'] = $current_question_item_body;
|
|
|
+ $current_question_item_body = '';
|
|
|
+ } elseif ($grand_parent_element == 'RESPONSE_LABEL') {
|
|
|
+ $last = '';
|
|
|
+ foreach ($exercise_info['question'][$current_question_ident]['answer'] as $key => $value) {
|
|
|
+ $last = $key;
|
|
|
+ }
|
|
|
+ $exercise_info['question'][$current_question_ident]['answer'][$last]['value'] = $current_question_item_body;
|
|
|
+ $current_question_item_body = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case 'RESPONSE_LID':
|
|
|
+
|
|
|
+ if (!isset($exercise_info['question'][$current_question_ident]['type'])) {
|
|
|
+ if ("multiple" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MCMA;
|
|
|
+ }
|
|
|
+ if ("single" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $current_question_item_body = '';
|
|
|
+
|
|
|
+ $current_answer_id = $attributes['IDENT'];
|
|
|
+ break;
|
|
|
+ case 'ITEMMETADATA':
|
|
|
+ $current_question_item_body = '';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ array_pop($element_pile);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * QTI1 element parser
|
|
|
+ * @param $parser
|
|
|
+ * @param $data
|
|
|
+ */
|
|
|
+function elementDataQti1($parser, $data)
|
|
|
+{
|
|
|
+ global $element_pile;
|
|
|
+ global $exercise_info;
|
|
|
+ global $current_question_ident;
|
|
|
+ global $current_answer_id;
|
|
|
+ global $current_match_set;
|
|
|
+ global $currentAssociableChoice;
|
|
|
+ global $current_question_item_body;
|
|
|
+ global $record_item_body;
|
|
|
+ global $non_HTML_tag_to_avoid;
|
|
|
+ global $current_inlinechoice_id;
|
|
|
+ global $cardinality;
|
|
|
+ global $lastLabelFieldName;
|
|
|
+ global $lastLabelFieldValue;
|
|
|
+
|
|
|
+ $current_element = end($element_pile);
|
|
|
+ if (sizeof($element_pile) >= 2) {
|
|
|
+ $parent_element = $element_pile[sizeof($element_pile) - 2];
|
|
|
+ } else {
|
|
|
+ $parent_element = "";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
|
|
|
+ $current_question_item_body .= $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch ($current_element) {
|
|
|
+ case 'FIELDLABEL':
|
|
|
+ if (!empty($data)) {
|
|
|
+ $lastLabelFieldName = $current_element;
|
|
|
+ $lastLabelFieldValue = $data;
|
|
|
+ }
|
|
|
+ case 'FIELDENTRY':
|
|
|
+ $current_question_item_body = $data;
|
|
|
+ switch ($lastLabelFieldValue) {
|
|
|
+ case 'cc_profile':
|
|
|
+
|
|
|
+
|
|
|
+ switch ($data) {
|
|
|
+ case 'cc.true_false.v0p1':
|
|
|
+
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
+ break;
|
|
|
+ case 'cc.multiple_choice.v0p1':
|
|
|
+
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
+ break;
|
|
|
+ case 'cc.multiple_response.v0p1':
|
|
|
+
|
|
|
+ $exercise_info['question'][$current_question_ident]['type'] = MCMA;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'cc_weighting':
|
|
|
+
|
|
|
+ $exercise_info['question'][$current_question_ident]['default_weighting'] = $lastLabelFieldValue;
|
|
|
+ break;
|
|
|
+ case 'assessment_question_identifierref':
|
|
|
+
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'MATTEXT':
|
|
|
+ if (!empty($current_question_item_body)) {
|
|
|
+ $current_question_item_body .= $data;
|
|
|
+ } else {
|
|
|
+ $current_question_item_body = $data;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'VAREQUAL':
|
|
|
+ $lastLabelFieldName = 'VAREQUAL';
|
|
|
+ $lastLabelFieldValue = $data;
|
|
|
+ break;
|
|
|
+ case 'SETVAR':
|
|
|
+ if ($parent_element == 'RESPCONDITION') {
|
|
|
+
|
|
|
+
|
|
|
+ $exercise_info['question'][$current_question_ident]['correct_answers'][] = $lastLabelFieldValue;
|
|
|
+ $exercise_info['question'][$current_question_ident]['weighting'][$lastLabelFieldValue] = $data;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+}
|