public function fromXML(SimpleXMLElement $xml) { $data = array("itemtype" => $this->itemType(), "title" => (string) $xml["title"], "stimulus" => qti_get_stimulus($xml->itemBody)); // check for a div with the item class name $itembodycontainer = null; foreach ($xml->itemBody->div as $div) { if (!isset($div["class"]) || (string) $div["class"] != "eqiat-mcr") { continue; } // get elements from here $itembodycontainer = $div; break; } // if there was none, get elements from itemBody if (is_null($itembodycontainer)) { $itembodycontainer = $xml->itemBody; } // there is one choiceInteraction if (count($itembodycontainer->choiceInteraction) != 1) { return 0; } // there is one responseDeclaration if (count($xml->responseDeclaration) != 1) { return 0; } // check cardinality is as expected if ($this->itemType() == "multipleResponse" && (string) $xml->responseDeclaration["cardinality"] != "multiple") { return 0; } if ($this->itemType() == "multipleChoice" && (string) $xml->responseDeclaration["cardinality"] != "single") { return 0; } // multiple choice must have maxchoices 1 and one correct response value if ($this->itemType() == "multipleChoice") { if (!isset($itembodycontainer->choiceInteraction["maxChoices"]) || (string) $itembodycontainer->choiceInteraction["maxChoices"] != "1") { return 0; } if (!isset($xml->responseDeclaration->correctResponse)) { return 0; } if (count($xml->responseDeclaration->correctResponse->value) != 1) { return 0; } } // get shuffle value $shuffle = isset($itembodycontainer->choiceInteraction["shuffle"]) && (string) $itembodycontainer->choiceInteraction["shuffle"] == "true"; if ($shuffle) { $data["shuffle"] = "on"; } // there is at least one option if (count($itembodycontainer->choiceInteraction->simpleChoice) == 0) { return 0; } // collect options and their identifiers $o = 0; $options = array(); foreach ($itembodycontainer->choiceInteraction->simpleChoice as $sc) { $options[] = (string) $sc["identifier"]; $data["option_{$o}_optiontext"] = (string) $sc; if ($shuffle && isset($sc["fixed"]) && (string) $sc["fixed"] == "true") { $data["option_{$o}_fixed"] = "on"; } $o++; } // check correct response makes sense; collect correct responses $correct = array(); if (count($xml->responseDeclaration->correctResponse) > 0) { foreach ($xml->responseDeclaration->correctResponse->value as $value) { $pos = array_search((string) $value, $options); if ($pos === false) { return 0; } $correct[] = $pos; } } if ($this->itemType() == "multipleChoice") { $data["correct"] = "option_" . $correct[0]; } else { foreach ($correct as $o) { $data["option_{$o}_correct"] = "on"; } } // get max and min choices if ($this->itemType() == "multipleResponse") { $data["maxchoices"] = isset($itembodycontainer->choiceInteraction["maxChoices"]) ? (string) $itembodycontainer->choiceInteraction["maxChoices"] : "0"; $data["minchoices"] = isset($itembodycontainer->choiceInteraction["minChoices"]) ? (string) $itembodycontainer->choiceInteraction["minChoices"] : "0"; } // get prompt $data["prompt"] = (string) $itembodycontainer->choiceInteraction->prompt; // not checking this properly at all but if modalFeedback elements exist // which look about right, use them for feedback foreach ($xml->modalFeedback as $mf) { $id = explode("_", (string) $mf["identifier"]); if (count($id) == 3 && $id[2] < count($options) && (string) $mf["outcomeIdentifier"] == "FEEDBACK") { $data["feedback"] = true; if ((string) $mf["showHide"] == "show") { $data["option_{$id[2]}_feedback_chosen"] = xml_remove_wrapper_element($mf->asXML()); } else { $data["option_{$id[2]}_feedback_unchosen"] = xml_remove_wrapper_element($mf->asXML()); } } } // get min score foreach ($xml->responseProcessing->responseCondition as $rc) { if (count($rc->responseIf) != 1) { continue; } if (count($rc->responseIf->lt) != 1) { continue; } $ltchildren = $rc->responseIf->lt->children(); if ($ltchildren[0]->getName() != "variable" || (string) $ltchildren[0]["identifier"] != "SCORE") { continue; } if ($ltchildren[1]->getName() != "baseValue") { continue; } $val = (string) $ltchildren[1]; if (count($rc->responseIf->setOutcomeValue) != 1) { continue; } if ((string) $rc->responseIf->setOutcomeValue["identifier"] != "SCORE") { continue; } if (count($rc->responseIf->setOutcomeValue->baseValue) != 1) { continue; } if ((string) $rc->responseIf->setOutcomeValue->baseValue != $val) { continue; } $data["minscore"] = $val; } // get max score foreach ($xml->responseProcessing->responseCondition as $rc) { if (count($rc->responseIf) != 1) { continue; } if (count($rc->responseIf->gt) != 1) { continue; } $gtchildren = $rc->responseIf->gt->children(); if ($gtchildren[0]->getName() != "variable" || (string) $gtchildren[0]["identifier"] != "SCORE") { continue; } if ($gtchildren[1]->getName() != "baseValue") { continue; } $val = (string) $gtchildren[1]; if (count($rc->responseIf->setOutcomeValue) != 1) { continue; } if ((string) $rc->responseIf->setOutcomeValue["identifier"] != "SCORE") { continue; } if (count($rc->responseIf->setOutcomeValue->baseValue) != 1) { continue; } if ((string) $rc->responseIf->setOutcomeValue->baseValue != $val) { continue; } $data["maxscore"] = $val; } // check response conditions for incrementing score if a particular // response is given $data["scoring"] = "exact"; foreach ($xml->responseProcessing->responseCondition as $rc) { if (count($rc->responseIf) != 1) { continue; } if (count($rc->responseIf->member) != 1) { continue; } $mchildren = $rc->responseIf->member->children(); if ($mchildren[0]->getName() != "baseValue" || (string) $mchildren[0]["baseType"] != "identifier") { continue; } $oid = (string) $mchildren[0]; if ($mchildren[1]->getName() != "variable" || (string) $mchildren[1]["identifier"] != "RESPONSE") { continue; } if (count($rc->responseIf->setOutcomeValue) != 1) { continue; } if ((string) $rc->responseIf->setOutcomeValue["identifier"] != "SCORE") { continue; } if (count($rc->responseIf->setOutcomeValue->sum) != 1) { continue; } if (count($rc->responseIf->setOutcomeValue->sum->children()) != 2) { continue; } if (count($rc->responseIf->setOutcomeValue->sum->variable) != 1 || (string) $rc->responseIf->setOutcomeValue->sum->variable["identifier"] != "SCORE") { continue; } if (count($rc->responseIf->setOutcomeValue->sum->baseValue) != 1) { continue; } $val = (string) $rc->responseIf->setOutcomeValue->sum->baseValue; $pos = array_search((string) $oid, $options); if ($pos === false) { continue; } $data["option_{$pos}_score"] = $val; $data["scoring"] = "cumulative"; } // see if it is in fact cumulative if ($data["scoring"] == "cumulative" && (!isset($data["minscore"]) || $data["minscore"] != 0 || isset($data["maxscore"]))) { $data["scoring"] = "custom"; } if ($data["scoring"] == "cumulative") { foreach ($options as $o => $option) { if (!isset($data["option_{$o}_score"]) || $data["option_{$o}_score"] != 1 && $data["option_{$o}_score"] != -1) { $data["scoring"] = "custom"; break; } } } // happy with that -- set data property and identifier $this->data = $data; $this->setQTIID((string) $xml["identifier"]); // multiple response with one correct answer is less than ideal if ($this->itemType() == "multipleresponse" && count($options) == 1) { return 192; } return 255; }
function qti_get_stimulus(SimpleXMLElement $ib) { $stimulus = simplexml_load_string('<stimulus xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1"/>', null); foreach ($ib->children() as $child) { if (containsQTIInteraction($child)) { continue; } // doesn't contain a QTI interaction so it counts as stimulus simplexml_append($stimulus, $child); } return xml_remove_wrapper_element($stimulus->asXML()); }