Reworking of the plug-in format for import/export files.

Each format is now in it's own subdirectory, which allows the
format to have as many files as it likes.  The formats are now
detected automatically (no need to edit lib.php anymore) and
the parent class is now in mod/quiz/format.php

Lastly, I added Paul Shew's new GIFT format.
This commit is contained in:
moodler
2003-12-12 07:35:55 +00:00
parent c3b736a119
commit 43bf9fc2d7
15 changed files with 1734 additions and 46 deletions
@@ -1,12 +1,12 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////
/// Default class for file imports/exports. //
/// format.php - Default format class for file imports/exports. //
/// //
/// Doesn't do everything on it's own -- it needs to be extended. //
////////////////////////////////////////////////////////////////////
// Included by ../import.php
// Included by import.php
class quiz_default_format {
-6
View File
@@ -1,6 +0,0 @@
This directory contains plug-in sub-modules to add
import-export formats to Moodle quizzes.
Each sub-module is a file containing a class that
contains functions for reading, writing, importing
and exporting quiz questions.
+12
View File
@@ -0,0 +1,12 @@
QUIZ FILE FORMATS FOR IMPORT/EXPORT
------------------------------------
This directory contains plug-in sub-modules to add
import-export formats to Moodle quizzes.
Each sub-module must contain at least a format.php file
containing a class that contains functions for reading,
writing, importing and exporting quiz questions.
Most of them are based on the class found in mod/quiz/format.php
+91
View File
@@ -0,0 +1,91 @@
<?PHP // $Id$
///
/// Written by Tom Robb <[email protected]> 2 November 2003
///
////////////////////////////////////////////////////////////////////////////
/// AIKEN FORMAT
///
/// This Moodle class provides all functions necessary to import and export
/// one-correct-answer multiple choice questions in this format:
///
/// Question text
/// A) Choice #1
/// B) Choice #2
/// C) Choice #3
/// D) Choice #4
/// ANSWER: B
/// (blank line next not necessary since "AN" at the beginning of a line
/// triggers the question input and causes input to start all over.
///
///Only ONE correct answer is allowed with no feedback responses.
///
///Be sure to reword "All of the above" type questions as "All of these" (etc.) so that choices can
/// be randomized
///
///This should work on WIN, Mac and Unix although only tested on Mac
///
////////////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
class quiz_file_format extends quiz_default_format {
//will this override default function?
function readquestions($lines){
$questions = array();
$endchar = chr(13);
foreach ($lines as $line) {
$stp = strpos($line,$endchar,0);
$newlines = explode($endchar,$line);
$foundQ = 0;
for ($i=0; $i < count($newlines);$i++){
$nowline = addslashes($newlines[$i]);
///Go through the arrage and build an object called $question
///When done, add $question to $questions
if (strlen($nowline)< 2) {
continue;
}
// This will show everyline when file is being processed
// print("$nowline<br>");
$leader = substr(ltrim($nowline),0,2);
if (strpos(".A)B)C)D)E)F)G)H)I)J)A.B.C.D.E.F.G.H.I.J.",$leader)>0){
//trim off the label and space
$question->answer[] = substr($nowline,3);
$question->fraction[] = 0;
continue;
}
if ($leader == "AN"){
$ans = trim(strstr($nowline,":"));
$ans = substr($ans,2,1);
//A becomes 0 since array starts from 0
$rightans = ord($ans) - 65;
$question->fraction[$rightans] = 1;
$questions[] = $question;
//clear array for next question set
$question = NULL;
continue;
} else {
//Must be the first line since no leader
$question->qtype = MULTICHOICE;
$question->name = substr($nowline,0,50);
$question->questiontext = $nowline;
$question->single = 1;
$question->feedback[] = "";
$question->usecase = 0; // Ignore case
$question->defaultgrade = 1;
$question->image = ""; // No images with this format
}
}
}
return $questions;
}
function readquestion($lines) {
//this is no longer needed but might still be called by default.php
return;
}
}
?>
+224
View File
@@ -0,0 +1,224 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////////////
/// Academy of Nursing format
///
/// Based on missingword.php
///
/// This Moodle class provides all functions necessary to import and export
/// one-correct-answer multiple choice questions in this format:
///
/// As soon as we begin to explore our body parts as infants
/// we become students of {=anatomy and physiology ~reflexology
/// ~science ~experiment}, and in a sense we remain students for life.
///
/// Each answer is separated with a tilde ~, and the correct answer is
/// prefixed with an equals sign =
///
/// Afterwards, all short-answer questions are randomly packed into
/// 4-answer matching questions.
///
////////////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
class quiz_file_format extends quiz_default_format {
function readquestion($lines) {
/// Given an array of lines known to define a question in
/// this format, this function converts it into a question
/// object suitable for processing and insertion into Moodle.
$question = NULL;
$text = implode($lines, " ");
/// Find answer section
$answerstart = strpos($text, "{");
if ($answerstart === false) {
if ($this->displayerrors) {
echo "<P>$text<P>Could not find a {";
}
return false;
}
$answerfinish = strpos($text, "}");
if ($answerfinish === false) {
if ($this->displayerrors) {
echo "<P>$text<P>Could not find a }";
}
return false;
}
$answerlength = $answerfinish - $answerstart;
$answertext = substr($text, $answerstart + 1, $answerlength - 1);
/// Save the new question text
$question->questiontext = addslashes(substr_replace($text, "_____", $answerstart, $answerlength+1));
$question->name = substr($question->questiontext, 0, 60)." ...";
/// Parse the answers
$answers = explode("~", $answertext);
$countanswers = count($answers);
switch ($countanswers) {
case 0: // invalid question
if ($this->displayerrors) {
echo "<P>No answers found in $answertext";
}
return false;
case 1:
$question->qtype = SHORTANSWER;
$answer = trim($answers[0]);
if ($answer[0] == "=") {
$answer = substr($answer, 1);
}
$question->answer[] = addslashes($answer);
$question->fraction[] = 1;
$question->feedback[] = "";
$question->usecase = 0; // Ignore case
$question->defaultgrade = 1;
$question->image = ""; // No images with this format
return $question;
default:
$question->qtype = MULTICHOICE;
$answers = swapshuffle($answers);
foreach ($answers as $key => $answer) {
$answer = trim($answer);
if ($answer[0] == "=") {
$question->fraction[$key] = 1;
$answer = substr($answer, 1);
} else {
$question->fraction[$key] = 0;
}
$question->answer[$key] = addslashes($answer);
$question->feedback[$key] = "";
}
$question->defaultgrade = 1;
$question->single = 1; // Only one answer is allowed
$question->image = ""; // No images with this format
return $question;
}
}
function importpostprocess() {
/// Goes through the questionids, looking for shortanswer questions
/// and converting random groups of 4 into matching questions.
/// Doesn't handle shortanswer questions with more than one answer
global $CFG;
print_heading(count($this->questionids)." ".get_string("questions", "quiz"));
$questionids = implode(',', $this->questionids);
if (!$shortanswers = get_records_select("quiz_questions",
"id IN ($questionids) AND qtype = ".SHORTANSWER,
"", "id,qtype")) {
return true;
}
$shortanswerids = array();
foreach ($shortanswers as $key => $shortanswer) {
$shortanswerids[] = $key;
}
$strmatch = get_string("match", "quiz")." (".$this->category->name.")";
$shortanswerids = swapshuffle($shortanswerids);
$count = $shortanswercount = count($shortanswerids);
$i = 1;
$matchcount = 0;
$question->category = $this->category->id;
$question->qtype = MATCH;
$question->questiontext = get_string("randomsamatchintro", "quiz");
$question->image = "";
while ($count > 4) {
$matchcount++;
$question->name = "$strmatch $i";
$question->subquestions = array();
$question->subanswers = array();
$extractids = implode(',', array_splice($shortanswerids, -4));
$count = count($shortanswerids);
$extracts = get_records_sql("SELECT q.questiontext, a.answer
FROM {$CFG->prefix}quiz_questions q,
{$CFG->prefix}quiz_shortanswer sa,
{$CFG->prefix}quiz_answers a
WHERE q.id in ($extractids)
AND sa.question = q.id
AND a.id = sa.answers");
if (count($extracts) != 4) {
print_object($extracts);
notify("Could not find exactly four shortanswer questions with ids: $extractids");
continue;
}
$question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
$question->version = 1; // Original version of this question
if (!$question->id = insert_record("quiz_questions", $question)) {
error("Could not insert new question!");
}
foreach ($extracts as $shortanswer) {
$question->subquestions[] = addslashes($shortanswer->questiontext);
$question->subanswers[] = addslashes($shortanswer->answer);
}
$result = quiz_save_question_options($question);
if (!empty($result->error)) {
notify("Error: $result->error");
}
if (!empty($result->notice)) {
notify($result->notice);
}
/// Delete the old short-answer questions
execute_sql("DELETE FROM {$CFG->prefix}quiz_questions WHERE id IN ($extractids)", false);
execute_sql("DELETE FROM {$CFG->prefix}quiz_shortanswer WHERE question IN ($extractids)", false);
execute_sql("DELETE FROM {$CFG->prefix}quiz_answers WHERE question IN ($extractids)", false);
}
if ($count) { /// Delete the remaining ones
foreach ($shortanswerids as $shortanswerid) {
delete_records("quiz_questions", "id", $shortanswerid);
delete_records("quiz_shortanswer", "question", $shortanswerid);
delete_records("quiz_answers", "question", $shortanswerid);
}
}
$info = "$shortanswercount ".get_string("shortanswer", "quiz").
" => $matchcount ".get_string("match", "quiz");
print_heading($info);
$options['category'] = $this->category->id;
echo "<center>";
print_single_button("multiple.php", $options, get_string("randomcreate", "quiz"));
echo "</center>";
return true;
}
}
?>
+252
View File
@@ -0,0 +1,252 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////////////
/// Blackboard 6.0 Format
///
/// This Moodle class provides all functions necessary to import and export
///
///
////////////////////////////////////////////////////////////////////////////
// Based on default.php, included by ../import.php
require_once ("$CFG->libdir/xmlize.php");
class quiz_file_format extends quiz_default_format {
/********************************
Need to re-compile php with zip support before testing this
function readdata($filename) {
/// Returns complete file with an array, one item per line
if (is_readable($filename)) {
$zip = zip_open($filename);
$zip_entry = $zip_read($zip);
if (strstr($zip_entry_name($zip_entry), "imsmanifest") == 0)
$zip_entry = $zip_read($zip); // skip past manifest file
if (zip_entry_open($zip, $zip_entry, "r")) {
$strbuf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
$buf = explode("\n", $strbuf);
zip_entry_close($zip_entry);
zip_close($zip);
return $buf;
} else {
zip_close($zip);
return false;
}
}
return false;
}
********************************/
function readquestions ($lines) {
/// Parses an array of lines into an array of questions,
/// where each item is a question object as defined by
/// readquestion().
$text = implode($lines, " ");
$xml = xmlize($text);
$questions = array();
process_tf($xml, $questions);
process_mc($xml, $questions);
process_fib($xml, $questions);
process_matching($xml, $questions);
return $questions;
}
}
//----------------------------------------
// Process True / False Questions
//----------------------------------------
function process_tf($xml, &$questions) {
$tfquestions = $xml["POOL"]["#"]["QUESTION_TRUEFALSE"];
for ($i = 0; $i < sizeof ($tfquestions); $i++) {
$question = NULL;
$question->qtype = TRUEFALSE;
$question->defaultgrade = 1;
$question->single = 1; // Only one answer is allowed
$question->image = ""; // No images with this format
$thisquestion = $tfquestions[$i];
// put questiontext in question object
$question->questiontext = addslashes(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
// put name in question object
$question->name = $question->questiontext;
$choices = $thisquestion["#"]["ANSWER"];
$correct_answer = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"][0]["@"]["answer_id"];
// first choice is true, second is false.
$id = $choices[0]["@"]["id"];
if (strcmp($id, $correct_answer) == 0) { // true is correct
$question->answer = 1;
$question->feedbacktrue = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
$question->feedbackfalse = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
} else { // false is correct
$question->answer = 0;
$question->feedbacktrue = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
$question->feedbackfalse = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
}
$questions[] = $question;
}
}
//----------------------------------------
// Process Multiple Choice Questions
//----------------------------------------
function process_mc($xml, &$questions) {
$mcquestions = $xml["POOL"]["#"]["QUESTION_MULTIPLECHOICE"];
for ($i = 0; $i < sizeof ($mcquestions); $i++) {
$question = NULL;
$question->qtype = MULTICHOICE;
$question->defaultgrade = 1;
$question->single = 1; // Only one answer is allowed
$question->image = ""; // No images with this format
$thisquestion = $mcquestions[$i];
// put questiontext in question object
$question->questiontext = addslashes(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
// put name of question in question object
$question->name = $question->questiontext;
$choices = $thisquestion["#"]["ANSWER"];
for ($j = 0; $j < sizeof ($choices); $j++) {
$choice = trim($choices[$j]["#"]["TEXT"][0]["#"]);
// put this choice in the question object.
$question->answer[$j] = addslashes($choice);
$id = $choices[$j]["@"]["id"];
$correct_answer_id = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"][0]["@"]["answer_id"];
// if choice is the answer, give 100%, otherwise give 0%
if (strcmp ($id, $correct_answer_id) == 0) {
$question->fraction[$j] = 1;
$question->feedback[$j] = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
} else {
$question->fraction[$j] = 0;
$question->feedback[$j] = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
}
}
$questions[] = $question;
}
}
//----------------------------------------
// Process Fill in the Blank Questions
//----------------------------------------
function process_fib($xml, &$questions) {
$fibquestions = $xml["POOL"]["#"]["QUESTION_FILLINBLANK"];
for ($i = 0; $i < sizeof ($fibquestions); $i++) {
$question = NULL;
$question->qtype = SHORTANSWER;
$question->defaultgrade = 1;
$question->usecase = 0; // Ignore case
$question->image = ""; // No images with this format
$thisquestion = $fibquestions[$i];
// put questiontext in question object
$question->questiontext = addslashes(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
// put name of question in question object
$question->name = $question->questiontext;
$answer = trim($thisquestion["#"]["ANSWER"][0]["#"]["TEXT"][0]["#"]);
$question->answer[] = addslashes($answer);
$question->fraction[] = 1;
$question->feedback[0] = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]));
$question->feedback[1] = addslashes(trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]));
$questions[] = $question;
}
}
//----------------------------------------
// Process Matching Questions
//----------------------------------------
function process_matching($xml, &$questions) {
$matchquestions = $xml["POOL"]["#"]["QUESTION_MATCH"];
for ($i = 0; $i < sizeof ($matchquestions); $i++) {
$question = NULL;
$question->qtype = MATCH;
$question->defaultgrade = 1;
$question->image = ""; // No images with this format
$thisquestion = $matchquestions[$i];
// put questiontext in question object
$question->questiontext = addslashes(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
// put name of question in question object
$question->name = $question->questiontext;
$choices = $thisquestion["#"]["CHOICE"];
for ($j = 0; $j < sizeof ($choices); $j++) {
$subquestion = NULL;
$choice = $choices[$j]["#"]["TEXT"][0]["#"];
$choice_id = $choices[$j]["@"]["id"];
$question->subanswers[] = addslashes(trim($choice));
$correctanswers = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"];
for ($k = 0; $k < sizeof ($correctanswers); $k++) {
if (strcmp($choice_id, $correctanswers[$k]["@"]["choice_id"]) == 0) {
$answer_id = $correctanswers[$k]["@"]["answer_id"];
$answers = $thisquestion["#"]["ANSWER"];
for ($m = 0; $m < sizeof ($answers); $m++) {
$answer = $answers[$m];
$current_ans_id = $answer["@"]["id"];
if (strcmp ($current_ans_id, $answer_id) == 0) {
$answer = $answer["#"]["TEXT"][0]["#"];
$question->subquestions[] = addslashes(trim($answer));
break;
}
}
break;
}
}
}
$questions[] = $question;
}
}
?>
+507
View File
@@ -0,0 +1,507 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////
/// Class for importing course test manager questions. //
/// //
/// //
////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
class quiz_file_format {
function importpreprocess($category) {
$this->category = $category; // Important
return true;
}
function importprocess($filename) {
global $CFG,$QUIZ_FILE_FORMAT,$strimportquestions,$form,$question_category,$category,$course,$THEME,
$hostname, $mdapath, $mdbpath;
if ((PHP_OS == "Linux") and isset($hostname)) {
$hostname = trim($hostname);
// test the ODBC socket server connection
// if failure, unset hostname and set hostname_access_error
$question_categories = $this->getquestioncategories($mdbpath, $mdapath, $hostname);
if (!$question_categories) {
$hostname_access_error = $hostname . " ";
unset($hostname);
} else {
$hostname_access_error = 0;
}
}
if ((PHP_OS == "Linux") and !isset($hostname)) {
// copy the file to a semi-permanent location
if (! $basedir = make_upload_directory("$course->id")) {
error("The site administrator needs to fix the file permissions for the data directory");
}
if (!isset($hostname_access_error)) {
$bname=basename($filename);
$cleanfilename = clean_filename($bname);
if ($cleanfilename) {
$newfile = "$basedir/$cleanfilename";
if (move_uploaded_file($filename, $newfile)) {
chmod($newfile, 0666);
} else {
notify(get_string("uploadproblem", "", $filename));
}
}
$filename = $newfile;
}
print_heading_with_help($strimportquestions, "import", "quiz");
print_simple_box_start("center", "", "$THEME->cellheading");
if ($hostname_access_error) { notify("couldn't connect to ODBC Socket Server on " . $hostname_access_error); }
echo "<form method=\"post\" action=\"import.php\">";
echo "<table cellpadding=5>";
echo "<tr><td align=right>";
echo "What is the hostname or IP address of the ODBC Socket Server:</td><td>";
echo " <input name=\"hostname\" type=\"text\" size=\"50\" value=\"".stripslashes($hostname_access_error)."\">";
echo " <input name=\"filename\" type=\"hidden\" value=\"".$filename."\">";
echo " <input name=\"category\" type=\"hidden\" value=\"".$category->id."\">";
echo " <input name=\"format\" type=\"hidden\" value=\"".$form->format."\">";
echo "</td><td>&nbsp;</td></tr>";
echo "<tr><td align=right>";
echo "What is the location of the database (.mdb file) on the Socket Server:</td><td>";
echo " <input name=\"mdbpath\" type=\"text\" size=\"50\" value=\"".stripslashes($mdbpath)."\">";
echo "</td><td>&nbsp;</td></tr>";
echo "<tr><td align=right>";
echo "What is the location of the system database (System.mda file) on the Socket Server:</td><td>";
echo " <input name=\"mdapath\" type=\"text\" size=\"50\" value=\"".stripslashes($mdapath)."\">";
echo "</td><td>&nbsp;</td></tr>";
echo "<tr><td>&nbsp;</td><td>";
echo " <input type=submit name=save value=\"Connect to Server\">";
echo "</td></tr>";
echo "</table>";
echo "</form>";
print_simple_box_end();
print_footer($course);
exit;
}
// we get here if running windows or after connect to ODBC socket server on linux
//
// this generates the page to choose categories of questions to import
//
if (!isset($question_category)) {
if (PHP_OS == "WINNT") {
// copy the file to a semi-permanent location
if (! $basedir = make_upload_directory("$course->id")) {
error("The site administrator needs to fix the file permissions for the data directory");
}
$bname=basename($filename);
$cleanfilename = clean_filename($bname);
if ($cleanfilename) {
$newfile = "$basedir/$cleanfilename";
if (move_uploaded_file($filename, $newfile)) {
chmod($newfile, 0666);
} else {
notify(get_string("uploadproblem", "", $filename));
}
}
$filename = $newfile;
}
// end of file copy
// don't have to do this on linux, since it's alreay been done in the test above
if (PHP_OS == "WINNT") { $question_categories = $this->getquestioncategories($filename); }
// print the intermediary form
if (!$categories = quiz_get_category_menu($course->id, true)) {
error("No categories!");
}
print_heading_with_help($strimportquestions, "import", "quiz");
print_simple_box_start("center", "", "$THEME->cellheading");
echo "<form method=\"post\" action=\"import.php\">";
echo "<table cellpadding=5>";
echo "<tr><td align=right>";
echo "Choose a category of questions to import:</td><td>";
asort($question_categories);
choose_from_menu($question_categories, "question_category","All Categories","All Categories", "", "allcategories");
echo " <input name=\"filename\" type=\"hidden\" value=\"".$filename."\">";
echo " <input name=\"category\" type=\"hidden\" value=\"".$category->id."\">";
echo " <input name=\"format\" type=\"hidden\" value=\"".$form->format."\">";
if (PHP_OS == "Linux") {
echo " <input name=\"hostname\" type=\"hidden\" value=\"".stripslashes(trim($hostname))."\">";
echo " <input name=\"mdbpath\" type=\"hidden\" value=\"".stripslashes($mdbpath)."\">";
echo " <input name=\"mdapath\" type=\"hidden\" value=\"".stripslashes($mdapath)."\">";
}
echo "</td><td>&nbsp;</td>";
echo "</tr><tr><td>&nbsp;</td><td>";
echo " <input type=submit name=save value=\"Import Questions\">";
echo "</td></tr>";
echo "</table>";
echo "</form>";
print_simple_box_end();
print_footer($course);
exit;
}
//
// this is the main import section
//
notify("Importing questions");
if (PHP_OS == "Linux") {
$hostname = trim($hostname);
$records = $this->getquestions($mdbpath,$question_category,$mdapath, $hostname);
} else {
$records = $this->getquestions($filename,$question_category);
}
foreach ($records as $qrec)
{
$question = NULL;
$question->image = ""; // No images with this format
if ($qrec[9] != "") {
$question->image = $qrec[9];
}
$question->defaultgrade = 1;
// 0 Selected
// 1 PracticeTestOK?
// 2 QuestionText
// 3 QuestionType
// 4 Option1Text
// 5 Option2Text
// 6 Option3Text
// 7 Option4Text
// 8 CorrectAnswer
// 9 Graphic
// 10 Module
// 11 ChapterNumber
// 12 PageNumber
$ref = "Answer can be found in chapter ". $qrec[11] . ", page " . $qrec[12] . ".";
switch ($qrec[3]) {
case 1:
$question->qtype = MULTICHOICE; // MULTICHOICE, SHORTANSWER, TRUEFALSE
// echo "<pre>";echo htmlspecialchars($qrec[2]); echo "</pre>";
$question->questiontext = addslashes(trim($qrec[2]));
// echo "<pre>";echo $question->questiontext; echo "</pre>";
$question->name = preg_replace("/<br>/", "", $question->questiontext);
$question->single = 1; // Only one answer is allowed -- used for multiple choicers
$fractionset = 0;
for ($i=4;$i<=7;$i++) {
if ($qrec[$i] != "") {
$question->answer[$i-3]=addslashes($qrec[$i]);
if ($qrec[8] == $i-3) { // if this is the index of CorrectAnswer
$question->fraction[$i-3] = 1;
$fractionset = 1;
} else {
$question->fraction[$i-3] = 0;
}
$question->feedback[$i-3] = (($qrec[8] == $i-3)?"Correct. ":"Incorrect. ") . $ref;
}
}
if ($fractionset == 0) { $question->fraction[1] = 1; }
break;
case 2: // TRUE FALSE
$question->qtype = TRUEFALSE;
$question->questiontext = addslashes(trim($qrec[2]));
$question->name = preg_replace("/<br>/", "", $question->questiontext);
// for TF, $question->answer should be 1 for true, 0 for false
if ($qrec[8] == "T") { $question->answer =1;} else { $question->answer = 0; }
// for TF, use $question->feedbacktrue and feedbackfalse
$question->feedbacktrue = (($qrec[8] =="T")?"Correct. ":"Incorrect. ") . $ref;
$question->feedbackfalse = (($qrec[8] =="F")?"Correct. ":"Incorrect. ") . $ref;
break;
case 3:
$question->qtype = SHORTANSWER;
$question->questiontext = addslashes(trim($qrec[2]));
// echo "<pre>";echo $question->questiontext; echo "</pre>";
$question->name = preg_replace("/<br>/", "", $question->questiontext);
$question->usecase=0; // Ignore case -- for SHORT ANSWER questions
$answers = explode("~", $qrec[8]);
$question->answer[0]=" ";
$question->fraction[0]=1;
for ($i=0;$i<count($answers);$i++) {
$question->answer[$i] = addslashes(trim($answers[$i]));
$question->feedback[$i] = $ref;
$question->fraction[$i] = 1; // 1 for 100%, 0 for none or somewhere in between
}
break;
case 4:
$question = 0;
notify("Cannot use essay questions - skipping question ". $qrec[2] . " " . $ref);
break;
default:
$question = 0;
notify("Misformatted Record. Question Skipped.");
break;
}
if ($question) { $questions[] = $question; }
}
$count = 0;
// process all the questions
if (PHP_OS == "WINNT") {
$filename = str_replace("\\\\","\\",$filename);
$filename = str_replace("/","\\",$filename);
}
foreach ($questions as $question) { // Process and store each question
$count++;
echo "<hr><p><b>$count</b>. ".stripslashes($question->questiontext)."</p>";
$question->category = $this->category->id;
$question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
$question->version = 1; // Original version of this question
if (!$question->id = insert_record("quiz_questions", $question)) {
error("Could not insert new question!");
}
$this->questionids[] = $question->id;
// Now to save all the answers and type-specific options
$result = quiz_save_question_options($question);
if (!empty($result->error)) {
notify($result->error);
$this->deletedatabase($filename);
return false;
}
if (!empty($result->notice)) {
notify($result->notice);
$this->deletedatabase($filename);
return true;
}
}
$this->deletedatabase($filename);
return true;
}
function importpostprocess() {
return true;
}
function deletedatabase($filename) {
if (! $this->fulldelete($filename)) {
echo "<BR>Error: Could not delete: $filename";
return false;
}
return true;
}
function getquestions($filename, $category, $mdapath="", $hostname="") {
if (($category == "allcategories") or ($category == "")) {
$sql = "SELECT * FROM TBQuestions";
} else {
$sql = "SELECT * FROM TBQuestions where module = '".$category."'";
}
if (PHP_OS == "WINNT") {
$ldb =& $this->connect_win($filename);
$qset = $ldb->Execute("$sql");
if ( $qset->RecordCount() > 0 ) {
$records = $qset->GetAssoc(true);
} else {
$this->err("There were no records in the database.",$dsn);
$ldb->Close();
return false;
}
$ldb->Close();
} else { // if PHP_OS == WINNT
// we have a linux installation
$result = $this->query_linux($sql,$filename, $mdapath,$hostname);
if ( count($result) > 0 ) {
// get rid of the ID field in the first column.
for($i=0;$i<count($result);$i++) {
foreach (array_keys($result[$i]) as $j) {
$records[$i][$j-1] = $result[$i][$j];
}
}
} else {
$this->err("There were no records in the database.",$dsn);
$ldb->Close();
return false;
}
// xml test and connect
} // PHP_OS TEST
return $records;
}
function getquestioncategories($filename, $mdapath="", $hostname="") {
global $CFG, $result;
$sql = "SELECT Distinct module FROM TBQuestions";
if (PHP_OS == "WINNT") {
$ldb =& $this->connect_win($filename);
$qset = $ldb->Execute("$sql");
if ( $qset->RecordCount() > 0 ) {
$records = $qset->GetArray(true);
foreach ($records as $record) {
$categories[$record[0]] = $record[0];
}
} else { // if recordcount
$this->err("There were no records in the database.",$dsn);
$ldb->Close();
return false;
}
$ldb->Close();
} else { // if PHP_OS == WINNT
// we have a linux installation
$result = $this->query_linux($sql, $filename, $mdapath, $hostname);
for($i=0;$i<count($result);$i++) {
$categories[$result[$i][0]] = $result[$i][0];
}
} // PHP_OS TEST
return $categories;
}
function query_linux($sql, $mdbpath, $mdapath, $hostname) {
global $result;
include_once("odbcsocketserver.class.php");
// set up socket server object to connect to remote host
$oTest = new ODBCSocketServer;
//Set the Hostname, port, and connection string
$oTest->sHostName = $hostname;
$oTest->nPort = 9628;
// $oTest->sConnectionString="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=C:\CTM\System.mda;DBQ=C:\CTM\of2K3\ctm.mdb;UID=Assess;PWD=VBMango;";
$oTest->sConnectionString="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=".
$mdapath.";DBQ=".$mdbpath.";UID=Assess;PWD=VBMango;";
// send and receive XML communication
$qResult = $oTest->ExecSQL($sql);
// set up XML parser to read the results
$xml_parser = xml_parser_create("US-ASCII");
xml_set_element_handler($xml_parser, "quiz_xmlstart", "quiz_xmlend");
xml_set_character_data_handler($xml_parser, "quiz_xmldata");
// parse the XML and get back the result set array
if (!xml_parse($xml_parser, $qResult)) {
$this->err("XML error: ".xml_error_string(xml_get_error_code($xml_parser))
." at line ".xml_get_current_line_number($xml_parser),$oTest->sConnectionString);
return false;
} else {
// echo("Successful XML parse. ");
// prepare the array for use in the pull-down
/* echo "<br>count of rows is ". count ($result);
echo "<pre>\n";
$qResult = HtmlSpecialChars($qResult);
echo $qResult;
echo "\n</pre>";
*/
xml_parser_free($xml_parser);
// $sResult = HtmlSpecialChars($qResult);
//echo("<pre>");
// echo($sResult);
// echo("</pre>");
return $result;
}
}
function connect_win($filename) {
global $CFG, $systemdb;
// first, verify the location of System.mda
if (!isset($systemdb)) {
$systemdb=$this->findfile("System.mda");
}
if (! $systemdb) {
$this->err("The system database System.mda cannot be found. Check that you've uploaded it to the course.",$dsn);
die;
}
$ldb = &ADONewConnection('access');
$dsn="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=".$systemdb.";DBQ=".$filename.";UID=Assess;PWD=VBMango;";
$dbconnected = $ldb->Connect($dsn);
if (! $dbconnected) {
$this->err("Moodle could not connect to the database.",$dsn);
die;
}
return $ldb;
}
function err($message, $dsn) {
echo "<font color=\"#990000\">";
echo "<p>Error: $message</p>";
echo "<p>ODBC File DSN: $dsn<br />";
echo "</font>";
}
function fulldelete($location) {
if (is_dir($location)) {
$currdir = opendir($location);
while ($file = readdir($currdir)) {
if ($file <> ".." && $file <> ".") {
$fullfile = $location."/".$file;
if (is_dir($fullfile)) {
if (!fulldelete($fullfile)) {
return false;
}
} else {
if (!unlink($fullfile)) {
return false;
}
}
}
}
closedir($currdir);
if (! rmdir($location)) {
return false;
}
} else {
if (!unlink($location)) {
return false;
}
}
return true;
}
function findfile($filename) {
global $CFG;
$dirs = $this->getcoursedirs();
$dirs[] = $CFG->dirroot."\mod\quiz\format";
foreach ($dirs as $dir) {
$file = $dir . "\System.mda";
// look for System.mda
if (is_file($file)) return $file;
}
return false;
}
function getcoursedirs() {
global $CFG;
// for every course in the system, find the root of the data directory
$courses = get_records_sql("select distinct id,fullname from ".$CFG->prefix."course");
$dirs = array();
if ($courses) {
foreach ($courses as $course) {
$dir = $CFG->dataroot . "/" . $course->id;
if (is_dir($dir)) { $dirs[] = $dir; }
}
}
return $dirs;
}
} // END OF CLASS
//Handler for starting elements
function quiz_xmlstart($parser, $name, $attribs) {
global $result,$row, $col, $incolumn;
$name = strtolower($name);
switch ($name) {
case "row":
$col=0;break;
case "column":
$incolumn = 1;break;
case "error":
break;
case "result":
$row = 0; break;
} // switch
}
//handler for the end of elements
function quiz_xmlend($parser, $name) {
global $result, $row, $col, $incolumn;
$name = strtolower($name);
switch ($name) {
case "row":
$row++;break;
case "column":
$incolumn = 0;
$col++;
break;
case "error":
break;
case "result":
break;
} // switch
} // function
//handler for character data
function quiz_xmldata($parser, $data) {
global $result, $row, $col, $incolumn;
if ($incolumn) { $result[$row][$col] = $result[$row][$col] . $data;
}
}
?>
-25
View File
@@ -1,25 +0,0 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////////////
/// CUSTOM FORMAT
///
/// This format provides a starting point for creating your own
/// import format.
///
/// See default.php for the functions that you may need to override
/// if you have different needs.
///
/// See missingword.php for an example of how it's done, and see
/// the top of ../lib.php for some constants you might need.
///
////////////////////////////////////////////////////////////////////////////
// Based on default.php, included by ../import.php
class quiz_file_format extends quiz_default_format {
}
?>
+274
View File
@@ -0,0 +1,274 @@
<?PHP // gift2
// version 1.0 BETA 2
////////////////////////////////////////////////////////////////////////////
/// GIFT: General Import Format Template
///
/// The GIFT format is a quick, easy to use method for teachers
/// writing questions as a text file. It supports true-false,
/// short answer and multiple-choice questions, as well as insertion
/// of a blank line for the missing word format. Below are examples
/// of the following question types: multiple choice, missing word,
/// true-false and short-answer.
///
/// Who's buried in Grant's tomb?{~Grant ~Jefferson =no one}
/// Grant is {~buried =entombed ~living} in Grant's tomb.
/// Grant is buried in Grant's tomb.{FALSE}
/// Who's buried in Grant's tomb?{=no one =nobody}
///
/// Optional question names are enclosed in double colon(::).
/// Answer feedback is indicated with hash mark (#).
/// Percentage answer weights immediately follow the tilde (for multiple
/// choice) or equal sign (for short answer), and are enclosed
/// in percent signs (% %).
///
/// ::Grant's Tomb::Grant is {
/// ~buried#No one is buried there.
/// =entombed#Right answer!
/// ~living#We hope not!
/// } in Grant's tomb.
///
/// Difficult question.{~wrong answer#comment on wrong answer
/// ~%50%half credit answer =full credit answer#well done!}
///
/// ::Jesus' hometown:: Jesus Christ was from {
/// =Nazareth#Yes! That's right!
/// =%75%Nazereth#Right, but misspelled.
/// =%25%Bethlehem#He was born here, but not raised here.}
///
/// This filter was written through the collaboration of numerous
/// members of the Moodle community. It was originally based on
/// the missingword format. In July 2003, Thomas Robb wrote the
/// original code for the percentage answer weight parser and comment
/// insertion. Paul Tsuchido Shew rewrote the filter in December 2003
/// incorporating community suggestions for a more robust question format,
/// and adding the question name parser, additional question types
/// and other features.
//////////////////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
class quiz_file_format extends quiz_default_format {
function answerweightparser(&$answer) {
$answer = substr($answer, 1); // removes initial %
$end_position = strpos($answer, "%");
$answer_weight = substr($answer, 0, $end_position); // gets weight as integer
$answer_weight = $answer_weight/100; // converts to percent
$answer = substr($answer, $end_position+1); // cleans up answer
/// To enable multiple answers (if fractional answer weights are assigned)
/// uncomment the following three lines.
/// if ($answer_weight > 0 and $answer_weight <> 1){
/// $question->single = 0; // ok many good answers
/// }
return $answer_weight;
}
function commentparser(&$answer) {
//Answer Comment parser
if (strpos($answer,"#") > 0){
$hashpos = strpos($answer,"#");
$comment = addslashes(substr($answer, $hashpos+1));
$answer = substr($answer, 0, $hashpos);
} else {
$comment = " ";
}
return $comment;
}
function readquestion($lines) {
/// Given an array of lines known to define a question in this format, this function
/// converts it into a question object suitable for processing and insertion into Moodle.
$question = NULL;
$comment = NULL;
$answer_weight_regex = "^%\-*([0-9]{1,2})\.?([0-9]*)%";
$text = implode(" ", $lines);
/// QUESTION NAME parser
$text = trim($text);
if (substr($text, 0, 2) == "::") {
$text = substr($text, 2);
$namefinish = strpos($text, "::");
if ($namefinish === false) {
$question->name = false;
// name will be assigned after processing question text below
} else {
$question->name = addslashes(trim(substr($text, 0, $namefinish)));
$text = substr($text, $namefinish+2); // Remove name from text
}
} else {
$question->name = false;
}
/// FIND ANSWER section
$answerstart = strpos($text, "{");
if ($answerstart === false) {
if ($this->displayerrors) {
echo "<P>$text<P>Could not find a {";
}
return false;
}
$answerfinish = strpos($text, "}");
if ($answerfinish === false) {
if ($this->displayerrors) {
echo "<P>$text<P>Could not find a }";
}
return false;
}
$answerlength = $answerfinish - $answerstart;
$answertext = trim(substr($text, $answerstart + 1, $answerlength - 1));
/// SAVE QUESTION TEXT without answer, inserting "_____" as necessary
if (substr($text, -1) == "}") {
/// no blank line if answers follow question, outside of closing punctuation
$question->questiontext = addslashes(substr_replace($text, "", $answerstart, $answerlength+1));
} else {
/// inserts blank line for missing word format
$question->questiontext = addslashes(substr_replace($text, "_____", $answerstart, $answerlength+1));
}
/// set question name if not already set
if ($question->name === false) {
$question->name = $question->questiontext;
}
/// ANSWERS
// Only Multiple-choice questions contain tilde ~
if (strstr($answertext, "~") !== FALSE) { // tilde conditional
///MULTIPLE CHOICE
$answertext = str_replace("=", "~=", $answertext);
$answers = explode("~", $answertext);
if (isset($answers[0])) {
$answers[0] = trim($answers[0]);
}
if (empty($answers[0])) {
array_shift($answers);
}
$countanswers = count($answers);
if ($countanswers < 2) { // MC $countanswers conditional
if ($this->displayerrors) {
echo "<P>Found tilde, but " . $countanswers . " answers in $answertext";
}
return false;
} else { // MC $countanswers conditional
$question->qtype = MULTICHOICE;
$question->single = 1; // Only one answer allowed by default
foreach ($answers as $key => $answer) {
$answer = trim($answer);
// determine answer weight
if ($answer[0] == "=") {
$answer_weight = 1;
$answer = substr($answer, 1);
} elseif (ereg($answer_weight_regex, $answer)) { // check for properly formatted answer weight
$answer_weight = $this->answerweightparser($answer);
} else { //default, i.e., wrong anwer
$answer_weight = 0;
}
$question->fraction[$key] = $answer_weight;
$comment = $this->commentparser($answer); // commentparser also cleans up $answer
$question->feedback[$key] = $comment;
$question->answer[$key] = addslashes($answer);
} // end foreach answer
$question->defaultgrade = 1;
$question->image = ""; // No images with this format
return $question;
} // end MC $countanswers conditional
/// Otherwise, begin parsing other question-types
} else { // tilde conditional
/// TRUEFALSE Question
$TF_check = $answertext;
if (strpos($answertext,"#") > 0){
// strip comments to check for TrueFalse question
$TF_check = trim(substr($answertext, 0, strpos($answertext,"#")));
}
if (($TF_check == "T") // TrueFalse/ShortAnswer QuestionType conditional
OR ($TF_check == "TRUE")
OR ($TF_check == "F")
OR ($TF_check == "FALSE")) {
$answer = $answertext;
$question->qtype = TRUEFALSE;
$comment = $this->commentparser($answer); // commentparser also cleans up $answer
if ($answer == "T" OR $answer == "TRUE") {
$question->answer = 1;
$question->feedbackfalse = $comment; //feedback if answer is wrong
} else {
$question->answer = 0;
$question->feedbacktrue = $comment; //feedback if answer is wrong
}
} else { // TrueFalse/ShortAnswer QuestionType conditional
/// SHORTANSWER Question
$answers = explode("=", $answertext);
if (isset($answers[0])) {
$answers[0] = trim($answers[0]);
}
if (empty($answers[0])) {
array_shift($answers);
}
if (count($answers) == 0) {
/// invalid question
if ($this->displayerrors) {
echo "<P>Found equals=, but no answers in $answertext";
}
return false;
} else {
$question->qtype = SHORTANSWER;
$question->usecase = 0; // Ignore case
foreach ($answers as $key => $answer) {
$answer = trim($answer);
// Answer Weight
if (ereg($answer_weight_regex, $answer)) { // check for properly formatted answer weight
$answer_weight = $this->answerweightparser($answer);
} else { //default, i.e., full-credit anwer
$answer_weight = 1;
}
$question->fraction[$key] = $answer_weight;
$comment = $this->commentparser($answer); //commentparser also cleans up $answer
$question->feedback[$key] = $comment;
$question->answer[$key] = addslashes($answer);
} // end foreach
} // end ount($answers) conditional
} // end TrueFalse/ShortAnswer QuestionType conditional
$question->defaultgrade = 1;
$question->image = ""; // No images with this format
return $question;
} // end tilde conditional
} // end function readquestion($lines)
}
?>
+156
View File
@@ -0,0 +1,156 @@
<?PHP // $Id$
/// Modified by Tom Robb 12 June 2003 to include percentage and comment insertion
/// facility.
////////////////////////////////////////////////////////////////////////////
/// MISSING WORD FORMAT
///
/// This Moodle class provides all functions necessary to import and export
/// one-correct-answer multiple choice questions in this format:
///
/// As soon as we begin to explore our body parts as infants
/// we become students of {=anatomy and physiology ~reflexology
/// ~science ~experiment}, and in a sense we remain students for life.
///
/// Each answer is separated with a tilde ~, and the correct answer is
/// prefixed with an equals sign =
///
/// Percentage weights can be included by following the tilde with the
/// desired percent. Comments can be included for each choice by following
/// the comment with a hash mark ("#") and the comment. Example:
///
/// This is {=the best answer#comment on the best answer ~75%a good
/// answer#comment on the good answer ~a wrong one#comment on the bad answer}
///
////////////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
class quiz_file_format extends quiz_default_format {
function readquestion($lines) {
/// Given an array of lines known to define a question in
/// this format, this function converts it into a question
/// object suitable for processing and insertion into Moodle.
$question = NULL;
///$comment added by T Robb
$comment = NULL;
$text = implode(" ", $lines);
/// Find answer section
$answerstart = strpos($text, "{");
if ($answerstart === false) {
if ($this->displayerrors) {
echo "<P>$text<P>Could not find a {";
}
return false;
}
$answerfinish = strpos($text, "}");
if ($answerfinish === false) {
if ($this->displayerrors) {
echo "<P>$text<P>Could not find a }";
}
return false;
}
$answerlength = $answerfinish - $answerstart;
$answertext = substr($text, $answerstart + 1, $answerlength - 1);
/// Save the new question text
$question->questiontext = addslashes(substr_replace($text, "_____", $answerstart, $answerlength+1));
$question->name = $question->questiontext;
/// Parse the answers
$answertext = str_replace("=", "~=", $answertext);
$answers = explode("~", $answertext);
if (isset($answers[0])) {
$answers[0] = trim($answers[0]);
}
if (empty($answers[0])) {
array_shift($answers);
}
$countanswers = count($answers);
switch ($countanswers) {
case 0: // invalid question
if ($this->displayerrors) {
echo "<P>No answers found in $answertext";
}
return false;
case 1:
$question->qtype = SHORTANSWER;
$answer = trim($answers[0]);
if ($answer[0] == "=") {
$answer = substr($answer, 1);
}
$question->answer[] = addslashes($answer);
$question->fraction[] = 1;
$question->feedback[] = "";
$question->usecase = 0; // Ignore case
$question->defaultgrade = 1;
$question->image = ""; // No images with this format
return $question;
default:
$question->qtype = MULTICHOICE;
foreach ($answers as $key => $answer) {
$answer = trim($answer);
// Tom's addition starts here
$answeight = 0;
if (strspn($answer,"1234567890%") > 0){
//Make sure that the percent sign is the last in the span
if (strpos($answer,"%") == strspn($answer,"1234567890%") - 1) {
$answeight0 = substr($answer,0,strspn($answer,"1234567890%"));
$answeight = round(($answeight0/100),2);
$answer = substr($answer,(strspn($answer,"1234567890%")));
}
}
if ($answer[0] == "="){
$answeight = 1;
}
//remove the protective underscore for leading numbers in answers
if ($answer[0] == "_"){
$answer = substr($answer, 1);
}
$answer = trim($answer);
if (strpos($answer,"#") > 0){
$hashpos = strpos($answer,"#");
$comment = addslashes(substr(($answer),$hashpos+1));
$answer = substr($answer,0,$hashpos);
} else {
$comment = " ";
}
// End of Tom's addition
if ($answer[0] == "=") {
# $question->fraction[$key] = 1;
$question->fraction[$key] = $answeight;
$answer = substr($answer, 1);
} else {
# $question->fraction[$key] = 0;
$question->fraction[$key] = $answeight;
}
$question->answer[$key] = addslashes($answer);
$question->feedback[$key] = $comment;
}
$question->defaultgrade = 1;
$question->single = 1; // Only one answer is allowed
$question->image = ""; // No images with this format
return $question;
}
}
}
?>
+162
View File
@@ -0,0 +1,162 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////////////
/// MULTIANSWER FORMAT
///
/// Created by Henrik Kaipe
///
////////////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
// REGULAR EXPRESSION CONSTANTS
// I do not know any way to make this easier
// Regexes are always awkard when defined but more comprehensible
// when used as constants in the executive code
// ANSWER_ALTERNATIVE regexes
define("ANSWER_ALTERNATIVE_FRACTION_REGEX",
'=|%(-?[0-9]+)%');
define("ANSWER_ALTERNATIVE_ANSWER_REGEX",
'[^~#}]+');
define("ANSWER_ALTERNATIVE_FEEDBACK_REGEX",
'[^~}]*');
define("ANSWER_ALTERNATIVE_REGEX",
'(' . ANSWER_ALTERNATIVE_FRACTION_REGEX .')?'
. '(' . ANSWER_ALTERNATIVE_ANSWER_REGEX . ')'
. '(#(' . ANSWER_ALTERNATIVE_FEEDBACK_REGEX .'))?');
// Parenthesis positions for ANSWER_ALTERNATIVE_REGEX
define("ANSWER_ALTERNATIVE_REGEX_PERCENTILE_FRACTION", 2);
define("ANSWER_ALTERNATIVE_REGEX_FRACTION", 1);
define("ANSWER_ALTERNATIVE_REGEX_ANSWER", 3);
define("ANSWER_ALTERNATIVE_REGEX_FEEDBACK", 5);
// NUMBER_FORMATED_ALTERNATIVE_ANSWER_REGEX is used
// for identifying numerical answers in ANSWER_ALTERNATIVE_REGEX_ANSWER
define("NUMBER_REGEX",
'-?(([0-9]+[.,]?[0-9]*|[.,][0-9]+)([eE][-+]?[0-9]+)?)');
define("NUMERICAL_ALTERNATIVE_REGEX",
'^(' . NUMBER_REGEX . ')(:' . NUMBER_REGEX . ')?$');
// Parenthesis positions for NUMERICAL_FORMATED_ALTERNATIVE_ANSWER_REGEX
define("NUMERICAL_CORRECT_ANSWER", 1);
define("NUMERICAL_ABS_ERROR_MARGIN", 6);
// Remaining ANSWER regexes
define("ANSWER_TYPE_DEF_REGEX",
'(NUMERICAL|NM)|(MULTICHOICE|MC)|(SHORTANSWER|SA|MW)');
define("ANSWER_START_REGEX",
'\{([0-9]*):(' . ANSWER_TYPE_DEF_REGEX . '):');
define("ANSWER_REGEX",
ANSWER_START_REGEX
. '(' . ANSWER_ALTERNATIVE_REGEX
. '(~'
. ANSWER_ALTERNATIVE_REGEX
. ')*)}' );
// Parenthesis positions for singulars in ANSWER_REGEX
define("ANSWER_REGEX_NORM", 1);
define("ANSWER_REGEX_ANSWER_TYPE_NUMERICAL", 3);
define("ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE", 4);
define("ANSWER_REGEX_ANSWER_TYPE_SHORTANSWER", 5);
define("ANSWER_REGEX_ALTERNATIVES", 6);
function extractMultiAnswerQuestion($text) {
$question = NULL;
$question->qtype= MULTIANSWER;
$question->questiontext= $text;
$question->answers= array();
$question->defaultgrade = 0; // Will be increased for each answer norm
for ($positionkey=1
; ereg(ANSWER_REGEX, $question->questiontext, $answerregs)
; ++$positionkey )
{
unset($multianswer);
$multianswer->positionkey = $positionkey;
$multianswer->norm = $answerregs[ANSWER_REGEX_NORM]
or $multianswer->norm = '1';
if ($answerregs[ANSWER_REGEX_ANSWER_TYPE_NUMERICAL]) {
$multianswer->answertype = NUMERICAL;
} else if($answerregs[ANSWER_REGEX_ANSWER_TYPE_SHORTANSWER]) {
$multianswer->answertype = SHORTANSWER;
} else if($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE]){
$multianswer->answertype = MULTICHOICE;
} else {
error("Cannot identify answertype $answerregs[2]");
return false;
}
$multianswer->alternatives= array();
$remainingalts = $answerregs[ANSWER_REGEX_ALTERNATIVES];
while (ereg(ANSWER_ALTERNATIVE_REGEX, $remainingalts, $altregs)) {
unset($alternative);
if ('=' == $altregs[ANSWER_ALTERNATIVE_REGEX_FRACTION]) {
$alternative->fraction = '1';
} else {
$alternative->fraction = .01 *
$altregs[ANSWER_ALTERNATIVE_REGEX_PERCENTILE_FRACTION]
or $alternative->fraction = '0';
}
$alternative->feedback = $altregs[ANSWER_ALTERNATIVE_REGEX_FEEDBACK];
if ($answerregs[ANSWER_REGEX_ANSWER_TYPE_NUMERICAL]
&& ereg(NUMERICAL_ALTERNATIVE_REGEX,
$altregs[ANSWER_ALTERNATIVE_REGEX_ANSWER],
$numregs) )
{
$alternative->answer = $numregs[NUMERICAL_CORRECT_ANSWER];
if ($numregs[NUMERICAL_ABS_ERROR_MARGIN]) {
$alternative->min = $numregs[NUMERICAL_CORRECT_ANSWER]
- $numregs[NUMERICAL_ABS_ERROR_MARGIN];
$alternative->max = $numregs[NUMERICAL_CORRECT_ANSWER]
+ $numregs[NUMERICAL_ABS_ERROR_MARGIN];
} else {
$alternative->min = $numregs[NUMERICAL_CORRECT_ANSWER];
$alternative->max = $numregs[NUMERICAL_CORRECT_ANSWER];
}
} else { // Min and max must stay undefined...
$alternative->answer =
$altregs[ANSWER_ALTERNATIVE_REGEX_ANSWER];
}
$multianswer->alternatives[] = $alternative;
$tmp = explode($altregs[0], $remainingalts, 2);
$remainingalts = $tmp[1];
}
$question->defaultgrade += $multianswer->norm;
$question->answers[] = $multianswer;
$question->questiontext = implode("{#$positionkey}",
explode($answerregs[0], $question->questiontext, 2));
}
return $question;
}
class quiz_file_format extends quiz_default_format {
function readquestions($lines) {
/// Parses an array of lines into an array of questions.
/// For this class the method has been simplified as
/// there can never be more than one question for a
/// multianswer import
$questions= array();
$thequestion= extractMultiAnswerQuestion(implode('',$lines));
if (!empty($thequestion)) {
$thequestion->name = $lines[0];
$questions[] = $thequestion;
}
return $questions;
}
}
?>
+19
View File
@@ -0,0 +1,19 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////////////
/// IMS QTI FORMAT
////////////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
class quiz_file_format extends quiz_default_format {
function importpreprocess($category) {
global $CFG;
error("Sorry, this format is not yet implemented!", "$CFG->wwwroot/mod/quiz/import.php?category=$category->id");
}
}
?>
+19
View File
@@ -0,0 +1,19 @@
<?PHP // $Id$
////////////////////////////////////////////////////////////////////////////
/// WEBCT FORMAT
////////////////////////////////////////////////////////////////////////////
// Based on format.php, included by ../../import.php
class quiz_file_format extends quiz_default_format {
function importpreprocess($category) {
global $CFG;
error("Sorry, this format is not yet implemented!", "$CFG->wwwroot/mod/quiz/import.php?category=$category->id");
}
}
?>
+16 -5
View File
@@ -49,12 +49,12 @@
} else { // Valid file is found
if (! is_readable("format/$form->format".".php")) {
if (! is_readable("format/$form->format/format.php")) {
error("Format not known ($form->format)");
}
require("format/default.php"); // Parent class
require("format/$form->format".".php");
require("format.php"); // Parent class
require("format/$form->format/format.php");
$format = new quiz_file_format();
@@ -83,6 +83,18 @@
error("No categories!");
}
$fileformats = get_list_of_plugins("mod/quiz/format");
$fileformatname = array();
foreach ($fileformats as $key => $fileformat) {
$formatname = get_string($fileformat, 'quiz');
if ($formatname == "[[$fileformat]]") {
$formatname = $fileformat; // Just use the raw folder name
}
$fileformatnames[$fileformat] = $formatname;
}
natcasesort($fileformatnames);
print_heading_with_help($strimportquestions, "import", "quiz");
print_simple_box_start("center", "", "$THEME->cellheading");
@@ -92,14 +104,13 @@
echo "<tr><td align=right>";
print_string("category", "quiz");
echo ":</td><td>";
asort($QUIZ_FILE_FORMAT);
choose_from_menu($categories, "category", "$category->id", "");
echo "</tr>";
echo "<tr><td align=right>";
print_string("fileformat", "quiz");
echo ":</td><td>";
choose_from_menu($QUIZ_FILE_FORMAT, "format", "custom", "");
choose_from_menu($fileformatnames, "format", "gift", "");
helpbutton("import", $strimportquestions, "quiz");
echo "</tr>";
-8
View File
@@ -34,14 +34,6 @@ $QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz")
MULTIANSWER => get_string("multianswer", "quiz")
);
$QUIZ_FILE_FORMAT = array ( "custom" => get_string("custom", "quiz"),
"missingword" => get_string("missingword", "quiz"),
"blackboard" => get_string("blackboard", "quiz"),
"aon" => "AON",
"aiken" => "Aiken",
"multianswer" => get_string("multianswer", "quiz"),
"coursetestmanager" => "Course Test Manager"
);
define("QUIZ_PICTURE_MAX_HEIGHT", "600"); // Not currently implemented
define("QUIZ_PICTURE_MAX_WIDTH", "600"); // Not currently implemented