/** * packItem implementation for QTI * @inheritdoc * @see {@link ItemPacker} * @throws InvalidArgumentException * @throws common_Exception */ public function packItem(core_kernel_classes_Resource $item, $lang = "") { $itemPack = null; $path = $this->getPath($item, $lang); $content = $this->getItemContent($path); //use the QtiParser to transform the QTI XML into an assoc array representation try { //load content $qtiParser = new QtiParser($content); //validate it $qtiParser->validate(); if (!$qtiParser->isValid()) { throw new common_Exception('Invalid QTI content : ' . $qtiParser->displayErrors(false)); } //parse $qtiItem = $qtiParser->load(); //then build the ItemPack from the parsed data if (!is_null($qtiItem)) { $itemPack = new ItemPack(self::$itemType, $qtiItem->toArray()); $itemPack->setAssetEncoders($this->getAssetEncoders()); $assetParser = new AssetParser($qtiItem, $path); $assetParser->setDeepParsing($this->isNestedResourcesInclusion()); foreach ($assetParser->extract($itemPack) as $type => $assets) { $itemPack->setAssets($type, $assets, $path); } } } catch (common_Exception $e) { throw new common_Exception('Unable to pack item ' . $item->getUri() . ' : ' . $e->getMessage()); } return $itemPack; }
/** * Validate and format (if possible) a QTI XML string * * @param string $qti * @return string * @throws QtiModelException */ public static function validateQtiXml($qti) { $returnValue = ''; // render and clean the xml $dom = new DOMDocument('1.0', 'UTF-8'); $dom->formatOutput = true; $dom->preserveWhiteSpace = false; $dom->validateOnParse = false; if ($dom->loadXML($qti)) { $returnValue = $dom->saveXML(); //in debug mode, systematically check if the save QTI is standard compliant if (DEBUG_MODE) { $parserValidator = new Parser($returnValue); $parserValidator->validate(); if (!$parserValidator->isValid()) { common_Logger::w('Invalid QTI output: ' . PHP_EOL . ' ' . $parserValidator->displayErrors()); common_Logger::d(print_r(explode(PHP_EOL, $returnValue), true)); throw new QtiModelException('invalid QTI item XML ' . PHP_EOL . ' ' . $parserValidator->displayErrors()); } } } else { $parserValidator = new Parser($qti); $parserValidator->validate(); if (!$parserValidator->isValid()) { throw new QtiModelException('Wrong QTI item output format'); } } return (string) $returnValue; }
/** * Validate a QTI XML string. * * @param string $qti File path or XML string * @throws QtiModelException */ public static function validateQtiXml($qti) { $dom = self::loadQtiXml($qti); $returnValue = $dom->saveXML(); $parserValidator = new Parser($returnValue); $parserValidator->validate(); if (!$parserValidator->isValid()) { common_Logger::w('Invalid QTI output: ' . PHP_EOL . ' ' . $parserValidator->displayErrors()); throw new QtiModelException('invalid QTI item XML ' . PHP_EOL . ' ' . $parserValidator->displayErrors()); } }
/** * test if alternative QTI profiles are managed correctly during parsing */ public function testParseAlternativeProfile() { $file = dirname(__FILE__) . '/samples/xml/qtiv2p1/alternativeProfiles/apip001.xml'; $qtiParser = new Parser($file); $qtiParser->validate(); if (!$qtiParser->isValid()) { $this->fail($qtiParser->displayErrors()); } $this->assertTrue($qtiParser->isValid()); $item = $qtiParser->load(); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item); $xml = simplexml_load_string($item->toXML()); $this->assertEquals('http://www.imsglobal.org/xsd/apip/apipv1p0/qtiitem/imsqti_v2p1', $xml->getNamespaces()['']); $this->assertNotNull($xml->apipAccessibility); }
/** * packItem implementation for QTI * @inheritdoc * @see {@link ItemPacker} * @throws InvalidArgumentException * @throws common_Exception */ public function packItem(core_kernel_classes_Resource $item, $lang, Directory $directory) { //use the QtiParser to transform the QTI XML into an assoc array representation $content = $this->getXmlByItem($item, $lang); //load content $qtiParser = new QtiParser($content); //validate it $qtiParser->validate(); if (!$qtiParser->isValid()) { throw new common_Exception('Invalid QTI content : ' . $qtiParser->displayErrors(false)); } //parse $qtiItem = $qtiParser->load(); return $this->packQtiItem($item, $lang, $qtiItem, $directory); }
/** * test the building and exporting out the items * @dataProvider itemProvider */ public function testToQTI($file) { $qtiParser = new Parser($file); $item = $qtiParser->load(); //test if content has been exported $qti = $item->toXML(); $this->assertFalse(empty($qti)); //test if it's a valid QTI file $tmpFile = $this->createFile('', uniqid('qti_', true) . '.xml'); file_put_contents($tmpFile, $qti); $this->assertTrue(file_exists($tmpFile)); $parserValidator = new Parser($tmpFile); $parserValidator->validate(); if (!$parserValidator->isValid()) { $this->fail($file . ' output invalid :' . $parserValidator->displayErrors() . ' -> ' . $qti); } }
protected function convertQtiFromV2p0ToV2p1($xml) { $returnValue = ''; $qtiParser = new Parser($xml); $qtiv2p1xsd = ROOT_PATH . 'taoQTI/models/classes/QTI/data/qtiv2p0/imsqti_v2p0.xsd'; $qtiParser->validate($qtiv2p1xsd); if ($qtiParser->isValid()) { $this->out('is a qti 2.0 item'); $item = $qtiParser->load(); if ($item instanceof Item) { $this->out('item loaded as QTI 2.1'); $returnValue = $item->toXML(); } } else { $this->out('does not seem to be a valid qti 2.0 item, attempt to load it anyway.'); $item = $qtiParser->load(); if ($item instanceof Item) { $this->out('Done! Item loaded as QTI 2.1'); $returnValue = $item->toXML(); } } return $returnValue; }
public function testFileParsingQtiPic() { $files = glob(dirname(__FILE__) . '/samples/xml/qtiv2p1/pic/*.xml'); //check if samples are loaded foreach ($files as $file) { $qtiParser = new Parser($file); $qtiParser->validate(); if (!$qtiParser->isValid()) { echo $qtiParser->displayErrors(); } $item = $qtiParser->load(); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item); } }
/** * Load a QTI item from a qti file in parameter. * * @access public * @author Somsack Sipasseuth, <*****@*****.**> * @param string file * @return oat\taoQtiItem\model\qti\Item */ public function loadItemFromFile($file) { $returnValue = null; if (is_string($file) && !empty($file)) { //validate the file to import try { $qtiParser = new Parser($file); $qtiParser->validate(); if (!$qtiParser->isValid()) { throw new ParsingException($qtiParser->displayErrors()); } $returnValue = $qtiParser->load(); } catch (ParsingException $pe) { throw new ParsingException($pe->getMessage()); } catch (Exception $e) { throw new Exception("Unable to load file {$file} caused by {$e->getMessage()}"); } } return $returnValue; }
protected function createQtiItemModel($qtiFile, $validate = true) { $qtiXml = Authoring::sanitizeQtiXml($qtiFile); //validate the file to import $qtiParser = new Parser($qtiXml); if ($validate) { $basePath = common_ext_ExtensionsManager::singleton()->getExtensionById('taoQtiItem')->getDir(); $qtiParser->validate(); if (!$qtiParser->isValid()) { $failedValidation = true; $eStrs = array(); foreach ($qtiParser->getErrors() as $libXmlError) { $eStrs[] = __('QTI-XML error at line %1$d "%2$s".', $libXmlError['line'], str_replace('[LibXMLError] ', '', trim($libXmlError['message']))); } // Make sure there are no duplicate... $eStrs = array_unique($eStrs); // Add sub-report. throw new ValidationException($qtiFile, $eStrs); } } $qtiItem = $qtiParser->load(); return $qtiItem; }
public function testParseRpTemplateDriven() { /** * a rp using standard template will be parsed into a template driven rp (for authoring purpose) */ $file = dirname(__FILE__) . '/samples/xml/qtiv2p1/responseProcessing/template.xml'; $qtiParser = new Parser($file); $qtiParser->validate(); $this->assertTrue($qtiParser->isValid()); $item = $qtiParser->load(); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\response\\TemplatesDriven', $item->getResponseProcessing()); //check if the rp is serialized correctly $xml = simplexml_load_string($item->toXML()); $this->assertEquals('http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct', (string) $xml->responseProcessing[0]['template']); /** * tao custom rp build using the tao "recognizable" response condition, with 2 interactions */ $file = dirname(__FILE__) . '/samples/xml/qtiv2p1/responseProcessing/templateDrivenMultiple.xml'; $qtiParser = new Parser($file); $qtiParser->validate(); $this->assertTrue($qtiParser->isValid()); $item = $qtiParser->load(); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\response\\TemplatesDriven', $item->getResponseProcessing()); //check if the rp is serialized correctly $xml = simplexml_load_string($item->toXML()); $this->assertEmpty((string) $xml->responseProcessing[0]['template']); /** * tao custom rp build using the tao "recognizable" response condition, with one interaction with the responseIdentifier RESPONSE_1 */ $file = dirname(__FILE__) . '/samples/xml/qtiv2p1/responseProcessing/templateDrivenSingle.xml'; $qtiParser = new Parser($file); $qtiParser->validate(); $this->assertTrue($qtiParser->isValid()); $item = $qtiParser->load(); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\response\\TemplatesDriven', $item->getResponseProcessing()); //check if the rp is serialized correctly $xml = simplexml_load_string($item->toXML()); $this->assertEmpty((string) $xml->responseProcessing[0]['template']); /** * tao custom rp build using the tao "recognizable" response condition, with one unique interaction that has the "right" responseIdentifier RESPONSE */ $file = dirname(__FILE__) . '/samples/xml/qtiv2p1/responseProcessing/templateDrivenSingleRESPONSE.xml'; $qtiParser = new Parser($file); $qtiParser->validate(); $this->assertTrue($qtiParser->isValid()); $item = $qtiParser->load(); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\response\\TemplatesDriven', $item->getResponseProcessing()); $xml = simplexml_load_string($item->toXML()); $this->assertEquals('http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response', (string) $xml->responseProcessing[0]['template']); }
/** * * @dataProvider templateDrivenRuleProvider */ public function testTemplateDrivenRules($file, $rpExpected) { $qtiParser = new Parser($file); $qtiParser->validate(); $this->assertTrue($qtiParser->isValid()); $item = $qtiParser->load(); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item); $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\response\\TemplatesDriven', $item->getResponseProcessing()); $rpJson = json_encode($item->getResponseProcessing()->toArray()['responseRules']); $this->assertEquals($rpExpected, $rpJson); }
protected function createQtiItemModel($qtiFile, $validate = true) { $qtiXml = Authoring::sanitizeQtiXml($qtiFile); //validate the file to import $qtiParser = new Parser($qtiXml); if ($validate) { $qtiParser->validate(); if (!$qtiParser->isValid()) { $eStrs = array(); foreach ($qtiParser->getErrors() as $libXmlError) { $eStrs[] = __('QTI-XML error at line %1$d "%2$s".', $libXmlError['line'], str_replace('[LibXMLError] ', '', trim($libXmlError['message']))); } // Make sure there are no duplicate... $eStrs = array_unique($eStrs); // Add sub-report. throw new ValidationException($qtiFile, $eStrs); } } $qtiItem = $qtiParser->load(); if (!$qtiItem && count($qtiParser->getErrors())) { $errors = []; foreach ($qtiParser->getErrors() as $error) { $errors[] = $error['message']; } throw new ValidationException($qtiFile, $errors); } return $qtiItem; }