Adding xml export
This commit is contained in:
Executable
+228
@@ -0,0 +1,228 @@
|
||||
<?php // $Id$
|
||||
//
|
||||
///////////////////////////////////////////////////////////////
|
||||
// XML import/export
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Based on default.php, included by ../import.php
|
||||
|
||||
class quiz_file_format extends quiz_default_format {
|
||||
|
||||
function indent_xhtml($source, $indenter = ' ') {
|
||||
// xml tidier-upper
|
||||
// (c) Ari Koivula http://ventionline.com
|
||||
|
||||
// Remove all pre-existing formatting.
|
||||
// Remove all newlines.
|
||||
$source = str_replace("\n", '', $source);
|
||||
$source = str_replace("\r", '', $source);
|
||||
// Remove all tabs.
|
||||
$source = str_replace("\t", '', $source);
|
||||
// Remove all space after ">" and before "<".
|
||||
$source = ereg_replace(">( )*", ">", $source);
|
||||
$source = ereg_replace("( )*<", "<", $source);
|
||||
|
||||
// Iterate through the source.
|
||||
$level = 0;
|
||||
$source_len = strlen($source);
|
||||
$pt = 0;
|
||||
while ($pt < $source_len) {
|
||||
if ($source{$pt} === '<') {
|
||||
// We have entered a tag.
|
||||
// Remember the point where the tag starts.
|
||||
$started_at = $pt;
|
||||
$tag_level = 1;
|
||||
// If the second letter of the tag is "/", assume its an ending tag.
|
||||
if ($source{$pt+1} === '/') {
|
||||
$tag_level = -1;
|
||||
}
|
||||
// If the second letter of the tag is "!", assume its an "invisible" tag.
|
||||
if ($source{$pt+1} === '!') {
|
||||
$tag_level = 0;
|
||||
}
|
||||
// Iterate throught the source until the end of tag.
|
||||
while ($source{$pt} !== '>') {
|
||||
$pt++;
|
||||
}
|
||||
// If the second last letter is "/", assume its a self ending tag.
|
||||
if ($source{$pt-1} === '/') {
|
||||
$tag_level = 0;
|
||||
}
|
||||
$tag_lenght = $pt+1-$started_at;
|
||||
|
||||
// Decide the level of indention for this tag.
|
||||
// If this was an ending tag, decrease indent level for this tag..
|
||||
if ($tag_level === -1) {
|
||||
$level--;
|
||||
}
|
||||
// Place the tag in an array with proper indention.
|
||||
$array[] = str_repeat($indenter, $level).substr($source, $started_at, $tag_lenght);
|
||||
// If this was a starting tag, increase the indent level after this tag.
|
||||
if ($tag_level === 1) {
|
||||
$level++;
|
||||
}
|
||||
// if it was a self closing tag, dont do shit.
|
||||
}
|
||||
// Were out of the tag.
|
||||
// If next letter exists...
|
||||
if (($pt+1) < $source_len) {
|
||||
// ... and its not an "<".
|
||||
if ($source{$pt+1} !== '<') {
|
||||
$started_at = $pt+1;
|
||||
// Iterate through the source until the start of new tag or until we reach the end of file.
|
||||
while ($source{$pt} !== '<' && $pt < $source_len) {
|
||||
$pt++;
|
||||
}
|
||||
// If we found a "<" (we didnt find the end of file)
|
||||
if ($source{$pt} === '<') {
|
||||
$tag_lenght = $pt-$started_at;
|
||||
// Place the stuff in an array with proper indention.
|
||||
$array[] = str_repeat($indenter, $level).substr($source, $started_at, $tag_lenght);
|
||||
}
|
||||
// If the next tag is "<", just advance pointer and let the tag indenter take care of it.
|
||||
} else {
|
||||
$pt++;
|
||||
}
|
||||
// If the next letter doesnt exist... Were done... well, almost..
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Replace old source with the new one we just collected into our array.
|
||||
$source = implode($array, "\n");
|
||||
return $source;
|
||||
}
|
||||
|
||||
|
||||
function export_file_extension() {
|
||||
// override default type so extension is .xml
|
||||
|
||||
return ".xml";
|
||||
}
|
||||
|
||||
function get_qtype( $type_id ) {
|
||||
// translates question type code number into actual name
|
||||
|
||||
switch( $type_id ) {
|
||||
case TRUEFALSE:
|
||||
$name = 'truefalse';
|
||||
break;
|
||||
case MULTICHOICE:
|
||||
$name = 'multichoice';
|
||||
break;
|
||||
case SHORTANSWER:
|
||||
$name = 'shortanswer';
|
||||
break;
|
||||
case NUMERICAL:
|
||||
$name = 'numerical';
|
||||
break;
|
||||
case MATCH:
|
||||
$name = 'matching';
|
||||
break;
|
||||
case DESCRIPTION:
|
||||
$name = 'description';
|
||||
break;
|
||||
case MULTIANSWER:
|
||||
$name = 'cloze';
|
||||
break;
|
||||
default:
|
||||
$name = '';
|
||||
error( "question type $type_id is not defined in get_qtype" );
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
function writetext( $raw ) {
|
||||
// generates <text></text> tags, processing raw text therein
|
||||
|
||||
// for now, don't allow any additional tags in text
|
||||
// otherwise xml rules would probably get broken
|
||||
$raw = strip_tags( $raw );
|
||||
|
||||
return "<text>$raw</text>\n";
|
||||
}
|
||||
|
||||
function writequestion( $question ) {
|
||||
// turns question into string
|
||||
// question reflects database fields for general question and specific to type
|
||||
|
||||
// initial string;
|
||||
$expout = "";
|
||||
|
||||
// add comment
|
||||
$expout .= "\n\n<!-- question: $question->id name: $question->name -->\n";
|
||||
|
||||
// add opening tag
|
||||
$question_type = $this->get_qtype( $question->qtype );
|
||||
$name_text = $this->writetext( $question->name );
|
||||
$question_text = $this->writetext( $question->questiontext );
|
||||
$expout .= "<question type=\"$question_type\">\n";
|
||||
$expout .= "<name>".$this->writetext($name_text)."</name>\n";
|
||||
$expout .= "<questiontext>".$this->writetext($question_text)."</questiontext>\n";
|
||||
|
||||
// output depends on question type
|
||||
switch($question->qtype) {
|
||||
case TRUEFALSE:
|
||||
$true_percent = round( $question->trueanswer->fraction * 100 );
|
||||
$false_percent = round( $question->falseanswer->fraction * 100 );
|
||||
// true answer
|
||||
$expout .= "<answer fraction=\"$true_percent\">\n";
|
||||
$expout .= $this->writetext("true")."\n";
|
||||
$expout .= "<feedback>".$this->writetext( $question->trueanswer->feedback )."</feedback>\n";
|
||||
$expout .= "</answer>\n";
|
||||
|
||||
|
||||
// false answer
|
||||
$expout .= "<answer fraction=\"$false_percent\">\n";
|
||||
$expout .= $this->writetext("false")."\n";
|
||||
$expout .= "<feedback>".$this->writetext( $question->falseanswer->feedback )."</feedback>\n";
|
||||
$expout .= "</answer>\n";
|
||||
break;
|
||||
case MULTICHOICE:
|
||||
foreach($question->answers as $answer) {
|
||||
$percent = round( $answer->fraction * 100 );
|
||||
$expout .= "<answer fraction=\"$percent\">\n";
|
||||
$expout .= $this->writetext( $answer->answer );
|
||||
$expout .= "<feedback>".$this->writetext( $answer->feedback )."</feedback>\n";
|
||||
$expout .= "</answer>\n";
|
||||
}
|
||||
break;
|
||||
case SHORTANSWER:
|
||||
foreach($question->answers as $answer) {
|
||||
$percent = 100 * $answer->fraction;
|
||||
$expout .= "<answer fraction=\"$percent\">\n";
|
||||
$expout .= $this->writetext( $answer->answer );
|
||||
$expout .= "<feedback>".$this->writetext( $answer->feedback )."</feedback>\n";
|
||||
$expout .= "</answer>\n";
|
||||
}
|
||||
break;
|
||||
case NUMERICAL:
|
||||
$expout .= "<min>$question->min</min>\n";
|
||||
$expout .= "<max>$question->max</max>\n";
|
||||
$expout .= "<feedback>".$this->writetext( $answer->feedback )."</feedback>\n";
|
||||
break;
|
||||
case MATCH:
|
||||
foreach($question->subquestions as $subquestion) {
|
||||
$expout .= "<subquestion>\n";
|
||||
$expout .= $this->writetext( $subquestion->questiontext );
|
||||
$expout .= "<answer>".$this->writetext( $subquestion->answertext )."</answer>\n";
|
||||
$expout .= "</subquestion>\n";
|
||||
}
|
||||
break;
|
||||
case DESCRIPTION:
|
||||
$expout .= "<!-- DESCRIPTION type is not supported -->\n";
|
||||
break;
|
||||
case MULTIANSWER:
|
||||
$expout .= "<!-- CLOZE type is not supported -->\n";
|
||||
break;
|
||||
default:
|
||||
error( "No handler for qtype $question->qtype for GIFT export" );
|
||||
}
|
||||
// close the question tag
|
||||
$expout .= "</question>\n";
|
||||
// run through xml tidy function
|
||||
return $this->indent_xhtml( $expout, ' ' );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user