Skip to content

Commit

Permalink
question types: MDL-20157 export_to_xml and import_from_xml functions…
Browse files Browse the repository at this point in the history
… for question types using extra_question_fields.

Thanks to Oleg Sychev for the implementation.
  • Loading branch information
tjhunt committed Sep 30, 2009
1 parent 7d4dfc4 commit 88bc20c
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 52 deletions.
38 changes: 25 additions & 13 deletions question/format.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ function provide_export() {
* @param object category the category object
*/
function setCategory( $category ) {
if (count($this->questions)){
debugging('You shouldn\'t call setCategory after setQuestions');
}
if (count($this->questions)){
debugging('You shouldn\'t call setCategory after setQuestions');
}
$this->category = $category;
}

Expand All @@ -59,9 +59,9 @@ function setCategory( $category ) {
* @param array of question objects
*/
function setQuestions( $questions ) {
if ($this->category !== null){
debugging('You shouldn\'t call setQuestions after setCategory');
}
if ($this->category !== null){
debugging('You shouldn\'t call setQuestions after setCategory');
}
$this->questions = $questions;
}

Expand All @@ -88,15 +88,15 @@ function setContexts($contexts) {
function setFilename( $filename ) {
$this->filename = $filename;
}
/**

/**
* set the "real" filename
* (this is what the user typed, regardless of wha happened next)
* @param string realfilename name of file as typed by user
*/
function setRealfilename( $realfilename ) {
$this->realfilename = $realfilename;
}
$this->realfilename = $realfilename;
}

/**
* set matchgrades
Expand Down Expand Up @@ -181,15 +181,27 @@ function error( $message, $text='', $questionname='' ) {
* @param data mixed The segment of data containing the question
* @param question object processed (so far) by standard import code if appropriate
* @param extra mixed any additional format specific data that may be passed by the format
* @param qtypehint hint about a question type from format
* @return object question object suitable for save_options() or false if cannot handle
*/
function try_importing_using_qtypes( $data, $question=null, $extra=null ) {
function try_importing_using_qtypes( $data, $question=null, $extra=null, $qtypehint='') {
global $QTYPES;

// work out what format we are using
$formatname = substr( get_class( $this ), strlen('qformat_'));
$formatname = substr(get_class($this), strlen('qformat_'));
$methodname = "import_from_$formatname";

//first try importing using a hint from format
if (!empty($qtypehint)) {
$qtype = $QTYPES[$qtypehint];
if (is_object($qtype) && method_exists($qtype, $methodname)) {
$question = $qtype->$methodname($data, $question, $this, $extra);
if ($question) {
return $question;
}
}
}

// loop through installed questiontypes checking for
// function to handle this question
foreach ($QTYPES as $qtype) {
Expand Down Expand Up @@ -377,7 +389,7 @@ function create_category_path($catpath, $delimiter='/') {
$catnames = explode($delimiter, $catpath);
$parent = 0;
$category = null;

// check for context id in path, it might not be there in pre 1.9 exports
$matchcount = preg_match('/^\$([a-z]+)\$$/', $catnames[0], $matches);
if ($matchcount==1) {
Expand Down
74 changes: 37 additions & 37 deletions question/format/xml/format.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ function provide_export() {

// IMPORT FUNCTIONS START HERE

/**
/**
* Translate human readable format name
* into internal Moodle code number
* @param string name format name from xml file
* @return int Moodle format code
*/
function trans_format( $name ) {
$name = trim($name);
$name = trim($name);

if ($name=='moodle_auto_format') {
$id = 0;
}
Expand Down Expand Up @@ -86,8 +86,8 @@ function import_text( $text ) {
* return the value of a node, given a path to the node
* if it doesn't exist return the default value
* @param array xml data to read
* @param array path path to node expressed as array
* @param mixed default
* @param array path path to node expressed as array
* @param mixed default
* @param bool istext process as text
* @param string error if set value must exist, return false and issue message if not
* @return mixed value
Expand Down Expand Up @@ -148,7 +148,7 @@ function import_headers( $question ) {
* import the common parts of a single answer
* @param array answer xml tree for single answer
* @return object answer object
*/
*/
function import_answer( $answer ) {
$fraction = $this->getpath( $answer, array('@','fraction'),0 );
$text = $this->getpath( $answer, array('#','text',0,'#'), '', true );
Expand All @@ -162,7 +162,7 @@ function import_answer( $answer ) {
}

/**
* import multiple choice question
* import multiple choice question
* @param array question question array from xml tree
* @return object question object
*/
Expand All @@ -187,7 +187,7 @@ function import_multichoice( $question ) {
}

// run through the answers
$answers = $question['#']['answer'];
$answers = $question['#']['answer'];
$a_count = 0;
foreach ($answers as $answer) {
$ans = $this->import_answer( $answer );
Expand Down Expand Up @@ -247,7 +247,7 @@ function import_truefalse( $question ) {
if ($answertext != 'true' && $answertext != 'false') {
$warning = true;
$answertext = $first ? 'true' : 'false'; // Old style file, assume order is true/false.
}
}
if ($answertext == 'true') {
$qo->answer = ($answer['@']['fraction'] == 100);
$qo->correctanswer = $qo->answer;
Expand Down Expand Up @@ -285,7 +285,7 @@ function import_shortanswer( $question ) {
$qo->usecase = $this->getpath($question, array('#','usecase',0,'#'), $qo->usecase );

// run through the answers
$answers = $question['#']['answer'];
$answers = $question['#']['answer'];
$a_count = 0;
foreach ($answers as $answer) {
$ans = $this->import_answer( $answer );
Expand All @@ -297,7 +297,7 @@ function import_shortanswer( $question ) {

return $qo;
}

/**
* import description type question
* @param array question question array from xml tree
Expand Down Expand Up @@ -398,7 +398,7 @@ function import_essay( $question ) {
$qo->qtype = ESSAY;

// get feedback
$qo->feedback = $this->getpath( $question, array('#','answer',0,'#','feedback',0,'#','text',0,'#'), '', true );
$qo->feedback = $this->getpath( $question, array('#','answer',0,'#','feedback',0,'#','text',0,'#'), '', true );

// get fraction - <fraction> tag is deprecated
$qo->fraction = $this->getpath( $question, array('@','fraction'), 0 ) / 100;
Expand Down Expand Up @@ -487,9 +487,9 @@ function import_calculated( $question ) {
$qo->dataset[$qo->datasetindex]->datasetitem[$qo->dataset[$qo->datasetindex]->itemindex] = new stdClass();
$qo->dataset[$qo->datasetindex]->datasetitem[$qo->dataset[$qo->datasetindex]->itemindex]->itemnumber = $datasetitem['#']['number'][0]['#']; //[0]['#']['number'][0]['#'] ; // [0]['numberitems'] ;//['#']['number'][0]['#'];// $datasetitems['#']['number'][0]['#'];
$qo->dataset[$qo->datasetindex]->datasetitem[$qo->dataset[$qo->datasetindex]->itemindex]->value = $datasetitem['#']['value'][0]['#'] ;//$datasetitem['#']['value'][0]['#'];
}
}
}

// echo "<pre>loaded qo";print_r($qo);echo "</pre>";

return $qo;
Expand Down Expand Up @@ -525,7 +525,7 @@ function readquestions($lines) {
// this converts xml to big nasty data structure
// the 0 means keep white space as it is (important for markdown format)
// print_r it if you want to see what it looks like!
$xml = xmlize( $text, 0 );
$xml = xmlize( $text, 0 );

// set up array to hold all our questions
$questions = array();
Expand All @@ -537,7 +537,7 @@ function readquestions($lines) {

if ($question_type=='multichoice') {
$qo = $this->import_multichoice( $question );
}
}
elseif ($question_type=='truefalse') {
$qo = $this->import_truefalse( $question );
}
Expand Down Expand Up @@ -571,9 +571,9 @@ function readquestions($lines) {
}
else {
// try for plugin support
// no default question, as the plugin can call
// no default question, as the plugin can call
// import_headers() itself if it wants to
if (!$qo=$this->try_importing_using_qtypes( $question )) {
if (!$qo = $this->try_importing_using_qtypes( $question, null, null, $question_type)) {
$notsupported = get_string( 'xmltypeunsupported','quiz',$question_type );
$this->error( $notsupported );
$qo = null;
Expand All @@ -592,7 +592,7 @@ function readquestions($lines) {

function export_file_extension() {
// override default type so extension is .xml

return ".xml";
}

Expand Down Expand Up @@ -672,7 +672,7 @@ function get_format( $id ) {
}

/**
* Convert internal single question code into
* Convert internal single question code into
* human readable form
* @param int id single question code
* @return string single question string
Expand All @@ -692,7 +692,7 @@ function get_single( $id ) {
}

/**
* generates <text></text> tags, processing raw text therein
* generates <text></text> tags, processing raw text therein
* @param int ilev the current indent level
* @param boolean short stick it on one line
* @return string formatted text
Expand All @@ -714,14 +714,14 @@ function writetext( $raw, $ilev=0, $short=true) {

return $xml;
}

function xmltidy( $content ) {
// can only do this if tidy is installed
if (extension_loaded('tidy')) {
$config = array( 'input-xml'=>true, 'output-xml'=>true, 'indent'=>true, 'wrap'=>0 );
$tidy = new tidy;
$tidy->parseString($content, $config, 'utf8');
$tidy->cleanRepair();
$tidy->cleanRepair();
return $tidy->value;
}
else {
Expand All @@ -748,11 +748,11 @@ function presave_process( $content ) {
/**
* Include an image encoded in base 64
* @param string imagepath The location of the image file
* @return string xml code segment
* @return string xml code segment
*/
function writeimage( $imagepath ) {
global $CFG;

if (empty($imagepath)) {
return '';
}
Expand Down Expand Up @@ -796,18 +796,18 @@ function writequestion( $question ) {
$expout .= " </category>\n";
$expout .= " </question>\n";
return $expout;
}
}
elseif ($question->qtype != MULTIANSWER) {
// for all question types except Close
$name_text = $this->writetext( $question->name );
$qtformat = $this->get_format($question->questiontextformat);
$question_text = $this->writetext( $question->questiontext );
$generalfeedback = $this->writetext( $question->generalfeedback );
$expout .= " <question type=\"$question_type\">\n";
$expout .= " <question type=\"$question_type\">\n";
$expout .= " <name>$name_text</name>\n";
$expout .= " <questiontext format=\"$qtformat\">\n";
$expout .= $question_text;
$expout .= " </questiontext>\n";
$expout .= " </questiontext>\n";
$expout .= " <image>{$question->image}</image>\n";
$expout .= $this->writeimage($question->image);
$expout .= " <generalfeedback>\n";
Expand Down Expand Up @@ -843,15 +843,15 @@ function writequestion( $question ) {
switch($question->qtype) {
case 'category':
// not a qtype really - dummy used for category switching
break;
break;
case TRUEFALSE:
foreach ($question->options->answers as $answer) {
$fraction_pc = round( $answer->fraction * 100 );
if ($answer->id == $question->options->trueanswer) {
$answertext = 'true';
} else {
$answertext = 'false';
}
}
$expout .= " <answer fraction=\"$fraction_pc\">\n";
$expout .= $this->writetext($answertext, 3) . "\n";
$expout .= " <feedback>\n";
Expand Down Expand Up @@ -981,7 +981,7 @@ function writequestion( $question ) {
$expout .= " </unit>\n";
}
$expout .= "</units>\n";
}
}
//The tag $question->export_process has been set so we get all the data items in the database
// from the function $QTYPES['calculated']->get_question_options(&$question);
// calculatedsimple defaults to calculated
Expand All @@ -999,7 +999,7 @@ function writequestion( $question ) {
$expout .= " <distribution>".$this->writetext($def->distribution)."</distribution>\n";
$expout .= " <minimum>".$this->writetext($def->minimum)."</minimum>\n";
$expout .= " <maximum>".$this->writetext($def->maximum)."</maximum>\n";
$expout .= " <decimals>".$this->writetext($def->decimals)."</decimals>\n";
$expout .= " <decimals>".$this->writetext($def->decimals)."</decimals>\n";
$expout .= " <itemcount>$def->itemcount</itemcount>\n";
if ($def->itemcount > 0 ) {
$expout .= " <dataset_items>\n";
Expand All @@ -1008,18 +1008,18 @@ function writequestion( $question ) {
$expout .= " <number>".$item->itemnumber."</number>\n";
$expout .= " <value>".$item->value."</value>\n";
$expout .= " </dataset_item>\n";
}
}
$expout .= " </dataset_items>\n";
$expout .= " <number_of_items>".$def-> number_of_items."</number_of_items>\n";
}
$expout .= "</dataset_definition>\n";
}
$expout .= "</dataset_definitions>\n";
}
}
$expout .= "</dataset_definitions>\n";
}
break;
default:
// try support by optional plugin
if (!$data = $this->try_exporting_using_qtypes( $question->qtype, $question )) {
if (!$data = $this->try_exporting_using_qtypes( $question->qtype, $question )) {
echo $OUTPUT->notification( get_string( 'unsupportedexport','qformat_xml',$QTYPES[$question->qtype]->local_name() ) );
}
$expout .= $data;
Expand Down
Loading

0 comments on commit 88bc20c

Please sign in to comment.