#!c:/perl/bin/Perl.exe ## ################################################################################################## ## Filename: qconverter_handler.pl ## Descripton: This tool creates a QTI XML file for each single-section WebCT quiz. ## It also converts the quizzes from Word Doc (as long as the questions ## are formatted in the required way). Right now, it's been tested to work ## with multiple choice, true and false, and fill in blank questions in English ## and Spanish. It works in Firefox, IE, and Safari. However, if there are images, ## you will have to upload those images later in the Sakai quizzes one by one. ## ## ## Author: Shawn Than Date: 11/15/2006 ## Melissa Zhuo ## ## Copyright (c) <2006> Claremont McKenna College ## Licensed under the Educational Community License version 1.0. ## For details go to http://opensource.org/licenses/ecl1.php ## ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ## INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR ## PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE ## FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ## ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## ########################################################################################################### use CGI; use strict; no strict 'subs'; print "Content-Type: text/html\n\n"; #get form variables my $q = new CGI; my $quiz_name = $q->param('quiz_name'); my $quiz_data = $q->param('quiz_data'); my $quiz_description = $q->param('quiz_description'); #make sure required fields are not empty if ($quiz_name eq "" or $quiz_data eq "") { print "quiz name or quiz data should not be empty."; exit; } #repalace Spanish charaters in data $quiz_name = &replaceSpanishChars($quiz_name); $quiz_data = &replaceSpanishChars($quiz_data); $quiz_description = &replaceSpanishChars($quiz_description); our $sakai_xml = ""; #hold the content of xml, global variable #creat a filename for the xml my $sakai_xml_filename = $quiz_name; $sakai_xml_filename =~ s/\s/\_/g; $sakai_xml_filename .= ".xml"; ### NOTE: Modify these following variables to meet your needs ### my $xml_path = "../"; #path where the xml file is saved on the server make sure files under this directory can be accessed from web browser so users can downlaod XML file #my $xml_path = "C://QuizConvert//"; my $xml_link = "/$sakai_xml_filename"; #the hypertext link to xml file our %spanishCharsHash = ( "Á" , "Á", "á" , "á", "É" , "É", "é" , "é", "Í" , "Í", "í" , "í", "Ñ" , "Ñ", "ñ" , "ñ", "Ó" , "Ó", "ó" , "ó", "Ú" , "Ú", "ú" , "ú", "Ü" , "Ü", "ü" , "ü", "«" , "«", "»" , "»", "¿" , "¿", "¡" , "¡" ); my $output = ""; $output .= < Sakai Quiz Converter EOF ; #get the xml contents and store in $sakai_xml. There are three parts: top, middle, and bottom &getTopXML($quiz_name); my @data = split(/\n/, $quiz_data); my ($question_number,$question_points,$question,$question_type,$correct_answer); my @answer; # store answers for multiple choice question my $ind = 0; #loop through the @data and process the data for (my $i=0; $i<=$#data; $i++) { chop($data[$i]) if $data[$i] =~ /\r$/; $data[$i] =~ s/^\s+//g; # remove the leading space if ($data[$i] ne "" and $data[$i] ne "Answer: ") { if ($data[$i] =~ /^Question(\s+)(\d+)(\s+)\((\d*\.?\d*)(\s+)point(s?)/) { $question_number = $2; $question_points = $4; }elsif ($data[$i] =~ /^\*/) { if ($data[$i] =~ /^\*([a-z])\.(\s*)(.*)/) { $correct_answer = $1; $answer[$ind] = $3; $ind++; $question_type = "Multiple Choice"; } elsif ($data[$i] =~ /^\*(.*)/) { $correct_answer = $1; $question_type = "Fill in Blank"; } }elsif ($data[$i] =~ /^([a-z])\.(\s*)(.*)/) { $answer[$ind] = $3; $ind++; }elsif ($data[$i] =~ /^Save answer/) { $output .= ""; #reset values $question_number = ""; $question_points = ""; $question_type = ""; $question = ""; @answer = (); $ind = 0; } else { $question .= "$data[$i] "; } } } $output .= "
Download the XML file and use the Sakai's Tests and Quizzes Import feature to import the quiz.
\n"; $output .= "Question $question_number: $question
"; $output .= "Point: $question_points
"; $output .= "Correct Answer: $correct_answer
"; $output .= "Question Type: $question_type
"; if ($question_type eq "Multiple Choice") { for (my $j=0; $j<=$#answer; $j++) { my $answer_number = $j+1; $output .= "  answer $answer_number: $answer[$j]
"; } } #check for missing data if ($question eq "") { print "Error!!! no question for Question $question_number "; exit; }elsif ($question_points eq "") { print "Error!!! no points for Question $question_number "; exit; }elsif ($correct_answer eq "") { print "Error!!! no correct answer for Question $question_number "; exit; }elsif ($question_type eq "") { print "Error!!! no question type for Question $question_number "; exit; } else { $question =~ s/(\x93|\x94)/"/g; &getMiddleXML($question,$correct_answer,$question_type,@answer); } $output .= "
"; $output .= ""; print $output; &getBottomXML(); #write the xml to a file open (FILE,">$xml_path$sakai_xml_filename"); print FILE $sakai_xml; close FILE; sub replaceSpanishChars { my $str = shift; while (my ($key, $value) = each(%spanishCharsHash)){ $str =~ s/$key/$value/g; } return $str; } sub getMiddleXML { my ($question,$correct_answer,$question_type,@answer) = @_; if ($question_type eq "Multiple Choice") { $sakai_xml .= < qmd_itemtype Multiple Choice TEXT_FORMAT HTML ITEM_OBJECTIVE ITEM_KEYWORD ITEM_RUBRIC hasRationale false EOF ; #fill in the answers for (my $j=0; $j<=$#answer; $j++) { my $char = chr(($j+65)); $sakai_xml .= < EOF ; } for (my $j=0; $j<=$#answer; $j++) { $sakai_xml .= < EOF ; } $sakai_xml .= < EOF ; ### response session for (my $j=0; $j<=25; $j++) { my $char = chr(($j+65)); my $response = (lc($char) eq $correct_answer)? "Correct" : "InCorrect"; $sakai_xml .= < $char 0.0 EOF ; } ### feedback session for (my $j=0; $j<=$#answer; $j++) { my $char = chr(($j+65)); my $order = "$char"."1"; $sakai_xml .= < EOF ; } $sakai_xml .= < EOF ; }elsif ($question_type eq "Fill in Blank") { $sakai_xml .= < qmd_itemtype Fill In the Blank TEXT_FORMAT HTML MUTUALLY_EXCLUSIVE True ITEM_OBJECTIVE ITEM_KEYWORD ITEM_RUBRIC $question $correct_answer 0 EOF ; } } sub getBottomXML { $sakai_xml .= < EOF ; } sub getTopXML { my $quiz_name = shift; $sakai_xml .= < P AUTHORS CREATOR SHOW_CREATOR True SCALENAME STRONGLY_AGREE EDIT_AUTHORS True EDIT_DESCRIPTION True DISPLAY_TEMPLATE True START_DATE END_DATE RETRACT_DATE CONSIDER_START_DATE False CONSIDER_END_DATE False CONSIDER_RETRACT_DATE False EDIT_END_DATE True EDIT_RETRACT_DATE True ASSESSMENT_RELEASED_TO EDIT_PUBLISH_ANONYMOUS True EDIT_AUTHENTICATED_USERS True ALLOW_IP CONSIDER_ALLOW_IP False CONSIDER_USERID False USERID PASSWORD EDIT_ALLOW_IP True EDIT_USERID True CONSIDER_DURATION False AUTO_SUBMIT True EDIT_DURATION True EDIT_AUTO_SUBMIT True NAVIGATION LINEAR QUESTION_LAYOUT I QUESTION_NUMBERING CONTINUOUS EDIT_NAVIGATION True EDIT_QUESTION_LAYOUT True EDIT_QUESTION_NUMBERING True LATE_HANDLING True MAX_ATTEMPTS 1 EDIT_LATE_HANDLING True EDIT_MAX_ATTEMPTS True AUTO_SAVE False EDIT_AUTO_SAVE True EDIT_ASSESSFEEDBACK True SUBMISSION_MESSAGE FINISH_URL EDIT_FINISH_URL True FEEDBACK_DELIVERY IMMEDIATE FEEDBACK_AUTHORING QUESTION FEEDBACK_DELIVERY_DATE EDIT_FEEDBACK_DELIVERY True EDIT_FEEDBACK_COMPONENTS True FEEDBACK_SHOW_CORRECT_RESPONSE True FEEDBACK_SHOW_STUDENT_SCORE True FEEDBACK_SHOW_ITEM_LEVEL True FEEDBACK_SHOW_SELECTION_LEVEL False FEEDBACK_SHOW_GRADER_COMMENT True FEEDBACK_SHOW_STATS True FEEDBACK_SHOW_QUESTION True FEEDBACK_SHOW_RESPONSE True ANONYMOUS_GRADING True GRADE_SCORE HIGHEST_SCORE GRADEBOOK_OPTIONS SELECTED EDIT_GRADEBOOK_OPTIONS True EDIT_ANONYMOUS_GRADING True EDIT_GRADE_SCORE True BGCOLOR BGIMG EDIT_BGCOLOR True EDIT_BGIMG True EDIT_ASSESSMENT_METADATA True EDIT_COLLECT_SECTION_METADATA True EDIT_COLLECT_ITEM_METADATA True ASSESSMENT_KEYWORDS ASSESSMENT_OBJECTIVES ASSESSMENT_RUBRICS COLLECT_SECTION_METADATA False COLLECT_ITEM_METADATA false LAST_MODIFIED_ON LAST_MODIFIED_BY templateInfo_isInstructorEditable true assessmentAuthor_isInstructorEditable true assessmentCreator_isInstructorEditable True description_isInstructorEditable true dueDate_isInstructorEditable true retractDate_isInstructorEditable true anonymousRelease_isInstructorEditable True authenticatedRelease_isInstructorEditable true ipAccessType_isInstructorEditable True passwordRequired_isInstructorEditable True timedAssessment_isInstructorEditable True timedAssessmentAutoSubmit_isInstructorEditable True itemAccessType_isInstructorEditable true displayChunking_isInstructorEditable true displayNumbering_isInstructorEditable true submissionModel_isInstructorEditable true lateHandling_isInstructorEditable true autoSave_isInstructorEditable True submissionMessage_isInstructorEditable true finalPageURL_isInstructorEditable true feedbackType_isInstructorEditable true feedbackComponents_isInstructorEditable true testeeIdentity_isInstructorEditable true toGradebook_isInstructorEditable true recordedScore_isInstructorEditable True bgColor_isInstructorEditable true bgImage_isInstructorEditable true metadataAssess_isInstructorEditable true metadataParts_isInstructorEditable True metadataQuestions_isInstructorEditable true
SECTION_OBJECTIVE SECTION_KEYWORD SECTION_RUBRIC EOF ; }