|
@@ -2,6 +2,7 @@
|
|
|
/* For licensing terms, see /license.txt */
|
|
|
|
|
|
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
|
|
|
+use Symfony\Component\DomCrawler\Crawler;
|
|
|
|
|
|
/**
|
|
|
* @copyright (c) 2001-2006 Universite catholique de Louvain (UCL)
|
|
@@ -65,12 +66,7 @@ function get_and_unzip_uploaded_exercise($baseWorkDir, $uploadPath)
|
|
|
*/
|
|
|
function import_exercise($file)
|
|
|
{
|
|
|
- global $exercise_info;
|
|
|
- global $element_pile;
|
|
|
- global $non_HTML_tag_to_avoid;
|
|
|
- global $record_item_body;
|
|
|
- // used to specify the question directory where files could be found in relation in any question
|
|
|
- global $questionTempDir;
|
|
|
+ global $exerciseInfo;
|
|
|
global $resourcesLinks;
|
|
|
|
|
|
$baseWorkDir = api_get_path(SYS_ARCHIVE_PATH).'qti2/';
|
|
@@ -85,12 +81,9 @@ function import_exercise($file)
|
|
|
}
|
|
|
|
|
|
// set some default values for the new exercise
|
|
|
- $exercise_info = [];
|
|
|
- $exercise_info['name'] = preg_replace('/.zip$/i', '', $file);
|
|
|
- $exercise_info['question'] = [];
|
|
|
- $element_pile = [];
|
|
|
- // create parser and array to retrieve info from manifest
|
|
|
- $element_pile = []; //pile to known the depth in which we are
|
|
|
+ $exerciseInfo = [];
|
|
|
+ $exerciseInfo['name'] = preg_replace('/.zip$/i', '', $file);
|
|
|
+ $exerciseInfo['question'] = [];
|
|
|
|
|
|
// if file is not a .zip, then we cancel all
|
|
|
if (!preg_match('/.zip$/i', $file)) {
|
|
@@ -106,7 +99,7 @@ function import_exercise($file)
|
|
|
|
|
|
// find the different manifests for each question and parse them.
|
|
|
$exerciseHandle = opendir($baseWorkDir);
|
|
|
- $file_found = false;
|
|
|
+ $fileFound = false;
|
|
|
$result = false;
|
|
|
$filePath = null;
|
|
|
$resourcesLinks = [];
|
|
@@ -125,7 +118,7 @@ function import_exercise($file)
|
|
|
if ($isQti) {
|
|
|
$result = qti_parse_file($baseWorkDir, $file, $questionFile);
|
|
|
$filePath = $baseWorkDir.$file;
|
|
|
- $file_found = true;
|
|
|
+ $fileFound = true;
|
|
|
} else {
|
|
|
$isManifest = isQtiManifest($baseWorkDir.'/'.$file.'/'.$questionFile);
|
|
|
if ($isManifest) {
|
|
@@ -139,7 +132,7 @@ function import_exercise($file)
|
|
|
if ($isQti) {
|
|
|
$result = qti_parse_file($baseWorkDir, '', $file);
|
|
|
$filePath = $baseWorkDir.'/'.$file;
|
|
|
- $file_found = true;
|
|
|
+ $fileFound = true;
|
|
|
} else {
|
|
|
$isManifest = isQtiManifest($baseWorkDir.'/'.$file);
|
|
|
if ($isManifest) {
|
|
@@ -149,7 +142,7 @@ function import_exercise($file)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!$file_found) {
|
|
|
+ if (!$fileFound) {
|
|
|
return 'NoXMLFileFoundInTheZip';
|
|
|
}
|
|
|
|
|
@@ -157,23 +150,20 @@ function import_exercise($file)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- $doc = new DOMDocument();
|
|
|
- $doc->load($filePath);
|
|
|
-
|
|
|
// 1. Create exercise.
|
|
|
$exercise = new Exercise();
|
|
|
- $exercise->exercise = $exercise_info['name'];
|
|
|
+ $exercise->exercise = $exerciseInfo['name'];
|
|
|
|
|
|
// Random QTI support
|
|
|
- if (isset($exercise_info['order_type'])) {
|
|
|
- if ($exercise_info['order_type'] == 'Random') {
|
|
|
+ if (isset($exerciseInfo['order_type'])) {
|
|
|
+ if ($exerciseInfo['order_type'] == 'Random') {
|
|
|
$exercise->setQuestionSelectionType(2);
|
|
|
$exercise->random = -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!empty($exercise_info['description'])) {
|
|
|
- $exercise->updateDescription(formatText(strip_tags($exercise_info['description'])));
|
|
|
+ if (!empty($exerciseInfo['description'])) {
|
|
|
+ $exercise->updateDescription(formatText(strip_tags($exerciseInfo['description'])));
|
|
|
}
|
|
|
|
|
|
$exercise->save();
|
|
@@ -181,7 +171,7 @@ function import_exercise($file)
|
|
|
$courseId = api_get_course_int_id();
|
|
|
if (!empty($last_exercise_id)) {
|
|
|
// For each question found...
|
|
|
- foreach ($exercise_info['question'] as $question_array) {
|
|
|
+ foreach ($exerciseInfo['question'] as $question_array) {
|
|
|
//2. Create question
|
|
|
$question = new Ims2Question();
|
|
|
$question->type = $question_array['type'];
|
|
@@ -300,7 +290,6 @@ function formatText($text)
|
|
|
*/
|
|
|
function qti_parse_file($exercisePath, $file, $questionFile)
|
|
|
{
|
|
|
- global $non_HTML_tag_to_avoid;
|
|
|
global $record_item_body;
|
|
|
global $questionTempDir;
|
|
|
|
|
@@ -311,10 +300,13 @@ function qti_parse_file($exercisePath, $file, $questionFile)
|
|
|
Display::addFlash(Display::return_message(get_lang('Error opening question\'s XML file'), 'error'));
|
|
|
|
|
|
return false;
|
|
|
- } else {
|
|
|
- $data = fread($fp, filesize($questionFilePath));
|
|
|
}
|
|
|
|
|
|
+ $data = fread($fp, filesize($questionFilePath));
|
|
|
+
|
|
|
+ //close file
|
|
|
+ fclose($fp);
|
|
|
+
|
|
|
//parse XML question file
|
|
|
//$data = str_replace(array('<p>', '</p>', '<front>', '</front>'), '', $data);
|
|
|
$data = ChamiloApi::stripGivenTags($data, ['p', 'front']);
|
|
@@ -327,53 +319,11 @@ function qti_parse_file($exercisePath, $file, $questionFile)
|
|
|
|
|
|
//used global variable start values declaration:
|
|
|
$record_item_body = false;
|
|
|
- $non_HTML_tag_to_avoid = [
|
|
|
- "SIMPLECHOICE",
|
|
|
- "CHOICEINTERACTION",
|
|
|
- "INLINECHOICEINTERACTION",
|
|
|
- "INLINECHOICE",
|
|
|
- "SIMPLEMATCHSET",
|
|
|
- "SIMPLEASSOCIABLECHOICE",
|
|
|
- "TEXTENTRYINTERACTION",
|
|
|
- "FEEDBACKINLINE",
|
|
|
- "MATCHINTERACTION",
|
|
|
- 'EXTENDEDTEXTINTERACTION',
|
|
|
- "ITEMBODY",
|
|
|
- "BR",
|
|
|
- "IMG",
|
|
|
- ];
|
|
|
-
|
|
|
- $question_format_supported = true;
|
|
|
- $xml_parser = xml_parser_create();
|
|
|
- xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, false);
|
|
|
|
|
|
- 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))) {
|
|
|
- // if reading of the xml file in not successful :
|
|
|
- // set errorFound, set error msg, break while statement
|
|
|
+ if ($qtiMainVersion != 2) {
|
|
|
Display::addFlash(
|
|
|
Display::return_message(
|
|
|
- get_lang('Error reading XML file').
|
|
|
- sprintf(
|
|
|
- '[%d:%d]',
|
|
|
- xml_get_current_line_number($xml_parser),
|
|
|
- xml_get_current_column_number($xml_parser)
|
|
|
- ),
|
|
|
+ get_lang('UnsupportedQtiVersion'),
|
|
|
'error'
|
|
|
)
|
|
|
);
|
|
@@ -381,682 +331,293 @@ function qti_parse_file($exercisePath, $file, $questionFile)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- //close file
|
|
|
- fclose($fp);
|
|
|
- if (!$question_format_supported) {
|
|
|
- Display::addFlash(
|
|
|
- Display::return_message(
|
|
|
- get_lang(
|
|
|
- 'Unknown question format in file %file',
|
|
|
- [
|
|
|
- '%file' => $questionFile,
|
|
|
- ]
|
|
|
- ),
|
|
|
- 'error'
|
|
|
- )
|
|
|
- );
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
+ parseQti2($data);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Function used by the SAX xml parser when the parser meets a opening tag.
|
|
|
+ * Function used to parser a QTI2 xml file.
|
|
|
*
|
|
|
- * @param object $parser xml parser created with "xml_parser_create()"
|
|
|
- * @param string $name name of the element
|
|
|
- * @param array $attributes
|
|
|
+ * @param string $xmlData
|
|
|
*/
|
|
|
-function startElementQti2($parser, $name, $attributes)
|
|
|
+function parseQti2($xmlData)
|
|
|
{
|
|
|
- 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 $exerciseInfo;
|
|
|
global $questionTempDir;
|
|
|
+ global $resourcesLinks;
|
|
|
|
|
|
- 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 = '';
|
|
|
- }
|
|
|
+ $crawler = new Crawler($xmlData);
|
|
|
+ $nodes = $crawler->filter('*');
|
|
|
+
|
|
|
+ $currentQuestionIdent = '';
|
|
|
+ $currentAnswerId = '';
|
|
|
+ $currentQuestionItemBody = '';
|
|
|
+ $cardinality = '';
|
|
|
+ $nonHTMLTagToAvoid = [
|
|
|
+ "simpleChoice",
|
|
|
+ "choiceInteraction",
|
|
|
+ "inlineChoiceInteraction",
|
|
|
+ "inlineChoice",
|
|
|
+ "soMPLEMATCHSET",
|
|
|
+ "simpleAssociableChoice",
|
|
|
+ "textEntryInteraction",
|
|
|
+ "feedbackInline",
|
|
|
+ "matchInteraction",
|
|
|
+ 'extendedTextInteraction',
|
|
|
+ "itemBody",
|
|
|
+ "br",
|
|
|
+ "img",
|
|
|
+ ];
|
|
|
+ $currentMatchSet = null;
|
|
|
|
|
|
- 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 {
|
|
|
- //in case of FIB question, we replace the IMS-QTI tag b y the correct answer between "[" "]",
|
|
|
- //we first save with claroline tags ,then when the answer will be parsed, the claroline tags will be replaced
|
|
|
- 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 />";
|
|
|
- }
|
|
|
+ /** @var DOMElement $node */
|
|
|
+ foreach ($nodes as $node) {
|
|
|
+ if ('#text' === $node->nodeName) {
|
|
|
+ continue;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- switch ($current_element) {
|
|
|
- case 'ASSESSMENTITEM':
|
|
|
- // retrieve current question
|
|
|
- $current_question_ident = $attributes['IDENTIFIER'];
|
|
|
- $exercise_info['question'][$current_question_ident] = [];
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'] = [];
|
|
|
- $exercise_info['question'][$current_question_ident]['correct_answers'] = [];
|
|
|
- $exercise_info['question'][$current_question_ident]['title'] = isset($attributes['TITLE']) ? $attributes['TITLE'] : '';
|
|
|
- $exercise_info['question'][$current_question_ident]['category'] = isset($attributes['CATEGORY']) ? $attributes['CATEGORY'] : '';
|
|
|
- $exercise_info['question'][$current_question_ident]['tempdir'] = $questionTempDir;
|
|
|
- break;
|
|
|
- case 'SECTION':
|
|
|
- //retrieve exercise name
|
|
|
- if (isset($attributes['TITLE']) && !empty($attributes['TITLE'])) {
|
|
|
- $exercise_info['name'] = $attributes['TITLE'];
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'RESPONSEDECLARATION':
|
|
|
- // Retrieve question type
|
|
|
- if ('multiple' == $attributes['CARDINALITY']) {
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MCMA;
|
|
|
- $cardinality = 'multiple';
|
|
|
- }
|
|
|
- if ('single' == $attributes['CARDINALITY']) {
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
- $cardinality = 'single';
|
|
|
- }
|
|
|
- //needed for FIB
|
|
|
- $current_answer_id = $attributes['IDENTIFIER'];
|
|
|
- break;
|
|
|
- case 'INLINECHOICEINTERACTION':
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = FIB;
|
|
|
- $exercise_info['question'][$current_question_ident]['subtype'] = 'LISTBOX_FILL';
|
|
|
- $current_answer_id = $attributes['RESPONSEIDENTIFIER'];
|
|
|
- break;
|
|
|
- case 'INLINECHOICE':
|
|
|
- $current_inlinechoice_id = $attributes['IDENTIFIER'];
|
|
|
- break;
|
|
|
- case 'TEXTENTRYINTERACTION':
|
|
|
- $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;
|
|
|
- //replace claroline tags
|
|
|
- break;
|
|
|
- case 'MATCHINTERACTION':
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MATCHING;
|
|
|
- break;
|
|
|
- case 'EXTENDEDTEXTINTERACTION':
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = FREE_ANSWER;
|
|
|
- $exercise_info['question'][$current_question_ident]['description'] = '';
|
|
|
- break;
|
|
|
- case 'SIMPLEMATCHSET':
|
|
|
- if (!isset($current_match_set)) {
|
|
|
- $current_match_set = 1;
|
|
|
- } else {
|
|
|
- $current_match_set++;
|
|
|
- }
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_match_set] = [];
|
|
|
- break;
|
|
|
- case 'SIMPLEASSOCIABLECHOICE':
|
|
|
- $currentAssociableChoice = $attributes['IDENTIFIER'];
|
|
|
- break;
|
|
|
- //retrieve answers id for MCUA and MCMA questions
|
|
|
- case 'SIMPLECHOICE':
|
|
|
- $current_answer_id = $attributes['IDENTIFIER'];
|
|
|
- if (!isset($exercise_info['question'][$current_question_ident]['answer'][$current_answer_id])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_answer_id] = [];
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'MAPENTRY':
|
|
|
- if ($parent_element == 'MAPPING' || $parent_element == 'MAPENTRY') {
|
|
|
- $answer_id = $attributes['MAPKEY'];
|
|
|
- if (!isset($exercise_info['question'][$current_question_ident]['weighting'])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['weighting'] = [];
|
|
|
+ switch ($node->nodeName) {
|
|
|
+ case 'assessmentItem':
|
|
|
+ $currentQuestionIdent = $node->getAttribute('identifier');
|
|
|
+
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent] = [
|
|
|
+ 'answer' => [],
|
|
|
+ 'correct_answers' => [],
|
|
|
+ 'title' => $node->getAttribute('title'),
|
|
|
+ 'category' => $node->getAttribute('category'),
|
|
|
+ 'type' => '',
|
|
|
+ 'tempdir' => $questionTempDir,
|
|
|
+ ];
|
|
|
+ break;
|
|
|
+ case 'section':
|
|
|
+ $title = $node->getAttribute('title');
|
|
|
+
|
|
|
+ if (!empty($title)) {
|
|
|
+ $exerciseInfo['name'] = $title;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'responseDeclaration':
|
|
|
+ if ('multiple' === $node->getAttribute('cardinality')) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['type'] = MCMA;
|
|
|
+ $cardinality = 'multiple';
|
|
|
}
|
|
|
- $exercise_info['question'][$current_question_ident]['weighting'][$answer_id] = $attributes['MAPPEDVALUE'];
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'MAPPING':
|
|
|
- if (isset($attributes['DEFAULTVALUE'])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['default_weighting'] = $attributes['DEFAULTVALUE'];
|
|
|
- }
|
|
|
- // no break ?
|
|
|
- case 'ITEMBODY':
|
|
|
- $record_item_body = true;
|
|
|
- $current_question_item_body = '';
|
|
|
- break;
|
|
|
- case 'IMG':
|
|
|
- $exercise_info['question'][$current_question_ident]['attached_file_url'] = $attributes['SRC'];
|
|
|
- break;
|
|
|
- case 'ORDER':
|
|
|
- if (isset($attributes['ORDER_TYPE'])) {
|
|
|
- $exercise_info['order_type'] = $attributes['ORDER_TYPE'];
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * Function used by the SAX xml parser when the parser meets a closing tag.
|
|
|
- *
|
|
|
- * @param $parser xml parser created with "xml_parser_create()"
|
|
|
- * @param $name name of the element
|
|
|
- */
|
|
|
-function endElementQti2($parser, $name)
|
|
|
-{
|
|
|
- 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;
|
|
|
-
|
|
|
- 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 = '';
|
|
|
- }
|
|
|
|
|
|
- //treat the record of the full content of itembody tag:
|
|
|
- if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
|
|
|
- $current_question_item_body .= "</".$name.">";
|
|
|
- }
|
|
|
+ if ('single' === $node->getAttribute('cardinality')) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['type'] = MCUA;
|
|
|
+ $cardinality = 'single';
|
|
|
+ }
|
|
|
|
|
|
- switch ($name) {
|
|
|
- case 'ITEMBODY':
|
|
|
- $record_item_body = false;
|
|
|
- if ($exercise_info['question'][$current_question_ident]['type'] == FIB) {
|
|
|
- $exercise_info['question'][$current_question_ident]['response_text'] = $current_question_item_body;
|
|
|
- } else {
|
|
|
- if ($exercise_info['question'][$current_question_ident]['type'] == FREE_ANSWER) {
|
|
|
- $current_question_item_body = trim($current_question_item_body);
|
|
|
- if (!empty($current_question_item_body)) {
|
|
|
- $exercise_info['question'][$current_question_ident]['description'] = $current_question_item_body;
|
|
|
+ $currentAnswerId = $node->getAttribute('identifier');
|
|
|
+ break;
|
|
|
+ case 'inlineChoiceInteraction':
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['type'] = FIB;
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['subtype'] = 'LISTBOX_FILL';
|
|
|
+ $currentAnswerId = $node->getAttribute('responseIdentifier');
|
|
|
+ break;
|
|
|
+ case 'inlineChoice':
|
|
|
+ $answerIdentifier = $exerciseInfo['question'][$currentQuestionIdent]['correct_answers'][$currentAnswerId];
|
|
|
+
|
|
|
+ if ($node->getAttribute('identifier') == $answerIdentifier) {
|
|
|
+ $currentQuestionItemBody = str_replace(
|
|
|
+ "**claroline_start**".$currentAnswerId."**claroline_end**",
|
|
|
+ "[".$node->nodeValue."]",
|
|
|
+ $currentQuestionItemBody
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ if (!isset($exerciseInfo['question'][$currentQuestionIdent]['wrong_answers'])) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['wrong_answers'] = [];
|
|
|
}
|
|
|
+
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['wrong_answers'][] = $node->nodeValue;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'textEntryInteraction':
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['type'] = FIB;
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['subtype'] = 'TEXTFIELD_FILL';
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['response_text'] = $currentQuestionItemBody;
|
|
|
+ break;
|
|
|
+ case 'matchInteraction':
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['type'] = MATCHING;
|
|
|
+ break;
|
|
|
+ case 'extendedTextInteraction':
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['type'] = FREE_ANSWER;
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['description'] = $node->nodeValue;
|
|
|
+ break;
|
|
|
+ case 'simpleMatchSet':
|
|
|
+ if (!isset($currentMatchSet)) {
|
|
|
+ $currentMatchSet = 1;
|
|
|
} else {
|
|
|
- $exercise_info['question'][$current_question_ident]['statement'] = $current_question_item_body;
|
|
|
+ $currentMatchSet++;
|
|
|
+ }
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentMatchSet] = [];
|
|
|
+ break;
|
|
|
+ case 'simpleAssociableChoice':
|
|
|
+ $currentAssociableChoice = $node->getAttribute('identifier');
|
|
|
+
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentMatchSet][$currentAssociableChoice] = trim($node->nodeValue);
|
|
|
+ break;
|
|
|
+ case 'simpleChoice':
|
|
|
+ $currentAnswerId = $node->getAttribute('identifier');
|
|
|
+ if (!isset($exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId])) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId] = [];
|
|
|
}
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- array_pop($element_pile);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param $parser
|
|
|
- * @param $data
|
|
|
- */
|
|
|
-function elementDataQti2($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 $resourcesLinks;
|
|
|
-
|
|
|
- $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 = '';
|
|
|
- }
|
|
|
-
|
|
|
- //treat the record of the full content of itembody tag (needed for question statment and/or FIB text:
|
|
|
-
|
|
|
- if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
|
|
|
- $current_question_item_body .= $data;
|
|
|
- }
|
|
|
|
|
|
- switch ($current_element) {
|
|
|
- case 'EXTENDEDTEXTINTERACTION':
|
|
|
- $exercise_info['question'][$current_question_ident]['description'] .= $data;
|
|
|
- break;
|
|
|
- case 'SIMPLECHOICE':
|
|
|
- if (!isset($exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['value'])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['value'] = trim($data);
|
|
|
- } else {
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['value'] .= ''.trim($data);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'FEEDBACKINLINE':
|
|
|
- if (!isset($exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['feedback'])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['feedback'] = trim($data);
|
|
|
- } else {
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['feedback'] .= ' '.trim($data);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'SIMPLEASSOCIABLECHOICE':
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_match_set][$currentAssociableChoice] = trim($data);
|
|
|
- break;
|
|
|
- case 'VALUE':
|
|
|
- if ($parent_element == 'CORRECTRESPONSE') {
|
|
|
- if ($cardinality == 'single') {
|
|
|
- $exercise_info['question'][$current_question_ident]['correct_answers'][$data] = $data;
|
|
|
+ if (!isset($exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId]['value'])) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId]['value'] = trim(
|
|
|
+ $node->nodeValue
|
|
|
+ );
|
|
|
} else {
|
|
|
- $exercise_info['question'][$current_question_ident]['correct_answers'][] = $data;
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId]['value'] .= ''
|
|
|
+ .trim($node->nodeValue);
|
|
|
}
|
|
|
- }
|
|
|
+ break;
|
|
|
+ case 'mapEntry':
|
|
|
+ if (in_array($node->parentNode->nodeName, ['mapping', 'mapEntry'])) {
|
|
|
+ $answer_id = $node->getAttribute('mapKey');
|
|
|
|
|
|
- // Getting score of free answer
|
|
|
- if ($grand_parent_element == 'OUTCOMEDECLARATION') {
|
|
|
- if (!empty(trim($data))) {
|
|
|
- $exercise_info['question'][$current_question_ident]['weighting'][0] = trim($data);
|
|
|
- }
|
|
|
- }
|
|
|
+ if (!isset($exerciseInfo['question'][$currentQuestionIdent]['weighting'])) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['weighting'] = [];
|
|
|
+ }
|
|
|
|
|
|
- break;
|
|
|
- case 'ITEMBODY':
|
|
|
- // Replace relative links by links to the documents in the course
|
|
|
- // $resourcesLinks is only defined by qtiProcessManifest()
|
|
|
- if (isset($resourcesLinks) && isset($resourcesLinks['manifest']) && isset($resourcesLinks['web'])) {
|
|
|
- foreach ($resourcesLinks['manifest'] as $key => $value) {
|
|
|
- $data = preg_replace('|'.$value.'|', $resourcesLinks['web'][$key], $data);
|
|
|
- }
|
|
|
- }
|
|
|
- $current_question_item_body .= $data;
|
|
|
- break;
|
|
|
- case 'INLINECHOICE':
|
|
|
- // if this is the right answer, then we must replace the claroline tags in the FIB text bye the answer between "[" and "]" :
|
|
|
- $answer_identifier = $exercise_info['question'][$current_question_ident]['correct_answers'][$current_answer_id];
|
|
|
- if ($current_inlinechoice_id == $answer_identifier) {
|
|
|
- $current_question_item_body = str_replace(
|
|
|
- "**claroline_start**".$current_answer_id."**claroline_end**",
|
|
|
- "[".$data."]",
|
|
|
- $current_question_item_body
|
|
|
- );
|
|
|
- } else {
|
|
|
- if (!isset($exercise_info['question'][$current_question_ident]['wrong_answers'])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['wrong_answers'] = [];
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['weighting'][$answer_id] = $node->getAttribute(
|
|
|
+ 'mappedValue'
|
|
|
+ );
|
|
|
}
|
|
|
- $exercise_info['question'][$current_question_ident]['wrong_answers'][] = $data;
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'MATTEXT':
|
|
|
- if ($grand_parent_element == 'FLOW_MAT' &&
|
|
|
- ($great_grand_parent_element == 'PRESENTATION_MATERIAL' || $great_grand_parent_element == 'SECTION')
|
|
|
- ) {
|
|
|
- if (!empty(trim($data))) {
|
|
|
- $exercise_info['description'] = $data;
|
|
|
+ break;
|
|
|
+ case 'mapping':
|
|
|
+ $defaultValue = $node->getAttribute('defaultValue');
|
|
|
+
|
|
|
+ if (!empty($defaultValue)) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['default_weighting'] = $defaultValue;
|
|
|
}
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
+ // no break ?
|
|
|
+ case 'itemBody':
|
|
|
+ $nodeValue = $node->nodeValue;
|
|
|
|
|
|
-/**
|
|
|
- * 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 = "";
|
|
|
- }
|
|
|
+ $currentQuestionItemBody = '';
|
|
|
|
|
|
- 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 {
|
|
|
- //in case of FIB question, we replace the IMS-QTI tag b y the correct answer between "[" "]",
|
|
|
- //we first save with claroline tags ,then when the answer will be parsed, the claroline tags will be replaced
|
|
|
- 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 />";
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ /** @var DOMElement $childNode */
|
|
|
+ foreach ($node->childNodes as $childNode) {
|
|
|
+ if ('#text' === $childNode->nodeName) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- switch ($current_element) {
|
|
|
- case 'ASSESSMENT':
|
|
|
- // This is the assessment element: we don't care, we just want questions
|
|
|
- if (!empty($attributes['TITLE'])) {
|
|
|
- $exercise_info['name'] = $attributes['TITLE'];
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'ITEM':
|
|
|
- //retrieve current question
|
|
|
- $current_question_ident = $attributes['IDENT'];
|
|
|
- $exercise_info['question'][$current_question_ident] = [];
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'] = [];
|
|
|
- $exercise_info['question'][$current_question_ident]['correct_answers'] = [];
|
|
|
- $exercise_info['question'][$current_question_ident]['tempdir'] = $questionTempDir;
|
|
|
- break;
|
|
|
- case 'SECTION':
|
|
|
- break;
|
|
|
- case 'RESPONSE_LID':
|
|
|
- // Retrieve question type
|
|
|
- if ("multiple" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
- $cardinality = 'multiple';
|
|
|
- }
|
|
|
- if ("single" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
- $cardinality = 'single';
|
|
|
- }
|
|
|
- //needed for FIB
|
|
|
- $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'];
|
|
|
- //set the placeholder for the answer to come (in endElementQti1)
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$current_answer_id] = '';
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'DECVAR':
|
|
|
- if ($parent_element == 'OUTCOMES' && $grand_parent_element == 'RESPROCESSING') {
|
|
|
- // The following attributes are available
|
|
|
- //$attributes['VARTYPE'];
|
|
|
- //$attributes['DEFAULTVAL'];
|
|
|
- //$attributes['MINVALUE'];
|
|
|
- //$attributes['MAXVALUE'];
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'VAREQUAL':
|
|
|
- if ($parent_element == 'CONDITIONVAR' && $grand_parent_element == 'RESPCONDITION') {
|
|
|
- // The following attributes are available
|
|
|
- //$attributes['RESPIDENT']
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'SETVAR':
|
|
|
- if ($parent_element == 'RESPCONDITION') {
|
|
|
- // The following attributes are available
|
|
|
- //$attributes['ACTION']
|
|
|
- }
|
|
|
- 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;
|
|
|
+ if (!in_array($childNode->nodeName, $nonHTMLTagToAvoid)) {
|
|
|
+ $currentQuestionItemBody .= '<'.$childNode->nodeName;
|
|
|
+
|
|
|
+ if ($childNode->attributes) {
|
|
|
+ foreach ($childNode->attributes as $attribute) {
|
|
|
+ $currentQuestionItemBody .= ' '.$attribute->nodeName.'="'.$attribute->nodeValue.'"';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $currentQuestionItemBody .= '>'
|
|
|
+ .$childNode->nodeValue
|
|
|
+ .'</'.$node->nodeName.'>';
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ('inlineChoiceInteraction' === $childNode->nodeName) {
|
|
|
+ $currentQuestionItemBody .= "**claroline_start**"
|
|
|
+ .$childNode->attr('responseIdentifier')
|
|
|
+ ."**claroline_end**";
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ('textEntryInteraction' === $childNode->nodeName) {
|
|
|
+ $correct_answer_value = $exerciseInfo['question'][$currentQuestionIdent]['correct_answers'][$currentAnswerId];
|
|
|
+ $currentQuestionItemBody .= "[".$correct_answer_value."]";
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ('br' === $childNode->nodeName) {
|
|
|
+ $currentQuestionItemBody .= '<br>';
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
-/**
|
|
|
- * 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;
|
|
|
- global $resourcesLinks;
|
|
|
+ // Replace relative links by links to the documents in the course
|
|
|
+ // $resourcesLinks is only defined by qtiProcessManifest()
|
|
|
+ if (isset($resourcesLinks) && isset($resourcesLinks['manifest']) && isset($resourcesLinks['web'])) {
|
|
|
+ foreach ($resourcesLinks['manifest'] as $key => $value) {
|
|
|
+ $nodeValue = preg_replace('|'.$value.'|', $resourcesLinks['web'][$key], $nodeValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $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 = "";
|
|
|
- }
|
|
|
+ $currentQuestionItemBody .= $node->firstChild->nodeValue;
|
|
|
|
|
|
- //treat the record of the full content of itembody tag :
|
|
|
- if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
|
|
|
- $current_question_item_body .= "</".$name.">";
|
|
|
- }
|
|
|
+ if ($exerciseInfo['question'][$currentQuestionIdent]['type'] == FIB) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['response_text'] = $currentQuestionItemBody;
|
|
|
+ } else {
|
|
|
+ if ($exerciseInfo['question'][$currentQuestionIdent]['type'] == FREE_ANSWER) {
|
|
|
+ $currentQuestionItemBody = trim($currentQuestionItemBody);
|
|
|
|
|
|
- switch ($name) {
|
|
|
- case 'MATTEXT':
|
|
|
- if ($parent_element == 'MATERIAL') {
|
|
|
- // For some reason an item in a hierarchy <item><presentation><material><mattext> doesn't seem to
|
|
|
- // catch the grandfather 'presentation', so we check for 'item' as a patch (great-grand-father)
|
|
|
- if ($grand_parent_element == 'PRESENTATION' || $grand_parent_element == 'ITEM') {
|
|
|
- $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;
|
|
|
+ if (!empty($currentQuestionItemBody)) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['description'] = $currentQuestionItemBody;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['statement'] = $currentQuestionItemBody;
|
|
|
}
|
|
|
- $exercise_info['question'][$current_question_ident]['answer'][$last]['value'] = $current_question_item_body;
|
|
|
- $current_question_item_body = '';
|
|
|
}
|
|
|
- }
|
|
|
- // no break ?
|
|
|
- case 'RESPONSE_LID':
|
|
|
- // Retrieve question type
|
|
|
- if (!isset($exercise_info['question'][$current_question_ident]['type'])) {
|
|
|
- if ("multiple" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MCMA;
|
|
|
+ break;
|
|
|
+ case 'img':
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['attached_file_url'] = $node->getAttribute('src');
|
|
|
+ break;
|
|
|
+ case 'order':
|
|
|
+ $orderType = $node->getAttribute('order_type');
|
|
|
+
|
|
|
+ if (!empty($orderType)) {
|
|
|
+ $exerciseInfo['order_type'] = $orderType;
|
|
|
}
|
|
|
- if ("single" == strtolower($attributes['RCARDINALITY'])) {
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
+ break;
|
|
|
+ case 'feedbackInline':
|
|
|
+ if (!isset($exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId]['feedback'])) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId] = trim(
|
|
|
+ $node->nodeValue
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['answer'][$currentAnswerId]['feedback'] .= ''
|
|
|
+ .trim(
|
|
|
+ $node->nodeValue
|
|
|
+ );
|
|
|
}
|
|
|
- }
|
|
|
- $current_question_item_body = '';
|
|
|
- //needed for FIB
|
|
|
- $current_answer_id = $attributes['IDENT'];
|
|
|
- break;
|
|
|
- case 'ITEMMETADATA':
|
|
|
- $current_question_item_body = '';
|
|
|
- break;
|
|
|
- }
|
|
|
- array_pop($element_pile);
|
|
|
-}
|
|
|
+ break;
|
|
|
+ case 'value':
|
|
|
+ if ('correctResponse' === $node->parentNode->nodeName) {
|
|
|
+ $nodeValue = trim($node->nodeValue);
|
|
|
|
|
|
-/**
|
|
|
- * 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;
|
|
|
- global $resourcesLinks;
|
|
|
-
|
|
|
- $current_element = end($element_pile);
|
|
|
- if (sizeof($element_pile) >= 2) {
|
|
|
- $parent_element = $element_pile[sizeof($element_pile) - 2];
|
|
|
- } else {
|
|
|
- $parent_element = "";
|
|
|
- }
|
|
|
- //treat the record of the full content of itembody tag (needed for question statment and/or FIB text:
|
|
|
+ if ('single' === $cardinality) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['correct_answers'][$nodeValue] = $nodeValue;
|
|
|
+ } else {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['correct_answers'][] = $nodeValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
|
|
|
- $current_question_item_body .= $data;
|
|
|
- }
|
|
|
+ if ('outcomeDeclaration' === $node->parentNode->parentNode->nodeName) {
|
|
|
+ $nodeValue = trim($node->nodeValue);
|
|
|
|
|
|
- switch ($current_element) {
|
|
|
- case 'FIELDLABEL':
|
|
|
- if (!empty($data)) {
|
|
|
- $lastLabelFieldName = $current_element;
|
|
|
- $lastLabelFieldValue = $data;
|
|
|
- }
|
|
|
- // no break ?
|
|
|
- case 'FIELDENTRY':
|
|
|
- $current_question_item_body = $data;
|
|
|
- switch ($lastLabelFieldValue) {
|
|
|
- case 'cc_profile':
|
|
|
- // The following values might be proprietary in MATRIX software. No specific reference
|
|
|
- // in QTI doc: http://www.imsglobal.org/question/qtiv1p2/imsqti_asi_infov1p2.html#1415855
|
|
|
- switch ($data) {
|
|
|
- case 'cc.true_false.v0p1':
|
|
|
- //this is a true-false question (translated to multiple choice in Chamilo because true-false comes with "I don't know")
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
- break;
|
|
|
- case 'cc.multiple_choice.v0p1':
|
|
|
- //this is a multiple choice (unique answer) question
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MCUA;
|
|
|
- break;
|
|
|
- case 'cc.multiple_response.v0p1':
|
|
|
- //this is a multiple choice (unique answer) question
|
|
|
- $exercise_info['question'][$current_question_ident]['type'] = MCMA;
|
|
|
- break;
|
|
|
+ if (!empty($nodeValue)) {
|
|
|
+ $exerciseInfo['question'][$currentQuestionIdent]['weighting'][0] = $nodeValue;
|
|
|
}
|
|
|
- break;
|
|
|
- case 'cc_weighting':
|
|
|
- //defines the total weight of the question
|
|
|
- $exercise_info['question'][$current_question_ident]['default_weighting'] = $lastLabelFieldValue;
|
|
|
- break;
|
|
|
- case 'assessment_question_identifierref':
|
|
|
- //placeholder - not used yet
|
|
|
- // Possible values are not defined by qti v1.2
|
|
|
- break;
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'MATTEXT':
|
|
|
- // Replace relative links by links to the documents in the course
|
|
|
- // $resourcesLinks is only defined by qtiProcessManifest()
|
|
|
- if (isset($resourcesLinks) && isset($resourcesLinks['manifest']) && isset($resourcesLinks['web'])) {
|
|
|
- foreach ($resourcesLinks['manifest'] as $key => $value) {
|
|
|
- $data = preg_replace('|'.$value.'|', $resourcesLinks['web'][$key], $data);
|
|
|
}
|
|
|
- }
|
|
|
- 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') {
|
|
|
- // The following attributes are available
|
|
|
- //$attributes['ACTION']
|
|
|
- $exercise_info['question'][$current_question_ident]['correct_answers'][] = $lastLabelFieldValue;
|
|
|
- $exercise_info['question'][$current_question_ident]['weighting'][$lastLabelFieldValue] = $data;
|
|
|
- }
|
|
|
- break;
|
|
|
+ break;
|
|
|
+ case 'mattext':
|
|
|
+ if ('flow_mat' === $node->parentNode->parentNode->nodeName &&
|
|
|
+ ('presentation_material' === $node->parentNode->parentNode->parentNode->nodeName ||
|
|
|
+ 'section' === $node->parentNode->parentNode->parentNode->nodeName
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ $nodeValue = trim($node->nodeValue);
|
|
|
+
|
|
|
+ if (!empty($nodeValue)) {
|
|
|
+ $exerciseInfo['description'] = $node->nodeValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|