Differences Between: [Versions 310 and 311]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Examview question importer. 19 * 20 * @package qformat_examview 21 * @copyright 2005 Howard Miller 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 require_once($CFG->libdir . '/xmlize.php'); 29 30 31 /** 32 * Examview question importer. 33 * 34 * @copyright 2005 Howard Miller 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class qformat_examview extends qformat_based_on_xml { 38 39 public $qtypes = array( 40 'tf' => 'truefalse', 41 'mc' => 'multichoice', 42 'yn' => 'truefalse', 43 'co' => 'shortanswer', 44 'ma' => 'match', 45 'mtf' => 99, 46 'nr' => 'numerical', 47 'pr' => 99, 48 'es' => 'essay', 49 'ca' => 99, 50 'ot' => 99, 51 'sa' => 'shortanswer', 52 ); 53 54 public $matchingquestions = array(); 55 56 public function provide_import() { 57 return true; 58 } 59 60 public function mime_type() { 61 return 'application/xml'; 62 } 63 64 /** 65 * unxmlise reconstructs part of the xml data structure in order 66 * to identify the actual data therein 67 * @param array $xml section of the xml data structure 68 * @return string data with evrything else removed 69 */ 70 protected function unxmlise( $xml ) { 71 // If it's not an array then it's probably just data. 72 if (!is_array($xml)) { 73 $text = s($xml); 74 } else { 75 // Otherwise parse the array. 76 $text = ''; 77 foreach ($xml as $tag => $data) { 78 // If tag is '@' then it's attributes and we don't care. 79 if ($tag!=='@') { 80 $text = $text . $this->unxmlise( $data ); 81 } 82 } 83 } 84 85 // Currently we throw the tags we found. 86 $text = strip_tags($text); 87 return $text; 88 } 89 90 public function parse_matching_groups($matchinggroups) { 91 if (empty($matchinggroups)) { 92 return; 93 } 94 foreach ($matchinggroups as $matchgroup) { 95 $newgroup = new stdClass(); 96 $groupname = trim($matchgroup['@']['name']); 97 $questiontext = $this->unxmlise($matchgroup['#']['text'][0]['#']); 98 $newgroup->questiontext = trim($questiontext); 99 $newgroup->subchoices = array(); 100 $newgroup->subquestions = array(); 101 $newgroup->subanswers = array(); 102 $choices = $matchgroup['#']['choices']['0']['#']; 103 foreach ($choices as $key => $value) { 104 if (strpos(trim($key), 'choice-') !== false) { 105 $key = strtoupper(trim(str_replace('choice-', '', $key))); 106 $newgroup->subchoices[$key] = trim($value['0']['#']); 107 } 108 } 109 $this->matching_questions[$groupname] = $newgroup; 110 } 111 } 112 113 protected function parse_ma($qrec, $groupname) { 114 $matchgroup = $this->matching_questions[$groupname]; 115 $phrase = trim($this->unxmlise($qrec['text']['0']['#'])); 116 $answer = trim($this->unxmlise($qrec['answer']['0']['#'])); 117 $answer = strip_tags( $answer ); 118 $matchgroup->mappings[$phrase] = $matchgroup->subchoices[$answer]; 119 $this->matching_questions[$groupname] = $matchgroup; 120 return null; 121 } 122 123 protected function process_matches(&$questions) { 124 if (empty($this->matching_questions)) { 125 return; 126 } 127 128 foreach ($this->matching_questions as $matchgroup) { 129 $question = $this->defaultquestion(); 130 $htmltext = s($matchgroup->questiontext); 131 $question->questiontext = $htmltext; 132 $question->questiontextformat = FORMAT_HTML; 133 $question->questiontextfiles = array(); 134 $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question')); 135 $question->qtype = 'match'; 136 $question = $this->add_blank_combined_feedback($question); 137 $question->subquestions = array(); 138 $question->subanswers = array(); 139 foreach ($matchgroup->subchoices as $subchoice) { 140 $fiber = array_keys ($matchgroup->mappings, $subchoice); 141 $subquestion = ''; 142 foreach ($fiber as $subquestion) { 143 $question->subquestions[] = $this->text_field($subquestion); 144 $question->subanswers[] = $subchoice; 145 } 146 if ($subquestion == '') { // Then in this case, $subchoice is a distractor. 147 $question->subquestions[] = $this->text_field(''); 148 $question->subanswers[] = $subchoice; 149 } 150 } 151 $questions[] = $question; 152 } 153 } 154 155 protected function cleanunicode($text) { 156 return str_replace('’', "'", $text); 157 } 158 159 public function readquestions($lines) { 160 // Parses an array of lines into an array of questions, 161 // where each item is a question object as defined by 162 // readquestion(). 163 164 $questions = array(); 165 $currentquestion = array(); 166 167 $text = implode(' ', $lines); 168 $text = $this->cleanunicode($text); 169 170 $xml = xmlize($text, 0); 171 if (!empty($xml['examview']['#']['matching-group'])) { 172 $this->parse_matching_groups($xml['examview']['#']['matching-group']); 173 } 174 175 $questionnode = $xml['examview']['#']['question']; 176 foreach ($questionnode as $currentquestion) { 177 if ($question = $this->readquestion($currentquestion)) { 178 $questions[] = $question; 179 } 180 } 181 182 $this->process_matches($questions); 183 return $questions; 184 } 185 186 public function readquestion($qrec) { 187 global $OUTPUT; 188 189 $type = trim($qrec['@']['type']); 190 $question = $this->defaultquestion(); 191 if (array_key_exists($type, $this->qtypes)) { 192 $question->qtype = $this->qtypes[$type]; 193 } else { 194 $question->qtype = null; 195 } 196 $question->single = 1; 197 198 // Only one answer is allowed. 199 $htmltext = $this->unxmlise($qrec['#']['text'][0]['#']); 200 201 $question->questiontext = $this->cleaninput($htmltext); 202 $question->questiontextformat = FORMAT_HTML; 203 $question->questiontextfiles = array(); 204 $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question')); 205 206 switch ($question->qtype) { 207 case 'multichoice': 208 $question = $this->parse_mc($qrec['#'], $question); 209 break; 210 case 'match': 211 $groupname = trim($qrec['@']['group']); 212 $question = $this->parse_ma($qrec['#'], $groupname); 213 break; 214 case 'truefalse': 215 $question = $this->parse_tf_yn($qrec['#'], $question); 216 break; 217 case 'shortanswer': 218 $question = $this->parse_co($qrec['#'], $question); 219 break; 220 case 'essay': 221 $question = $this->parse_es($qrec['#'], $question); 222 break; 223 case 'numerical': 224 $question = $this->parse_nr($qrec['#'], $question); 225 break; 226 break; 227 default: 228 echo $OUTPUT->notification(get_string('unknownorunhandledtype', 'question', $type)); 229 $question = null; 230 } 231 232 return $question; 233 } 234 235 protected function parse_tf_yn($qrec, $question) { 236 $choices = array('T' => 1, 'Y' => 1, 'F' => 0, 'N' => 0 ); 237 $answer = trim($qrec['answer'][0]['#']); 238 $question->answer = $choices[$answer]; 239 $question->correctanswer = $question->answer; 240 if ($question->answer == 1) { 241 $question->feedbacktrue = $this->text_field(get_string('correct', 'question')); 242 $question->feedbackfalse = $this->text_field(get_string('incorrect', 'question')); 243 } else { 244 $question->feedbacktrue = $this->text_field(get_string('incorrect', 'question')); 245 $question->feedbackfalse = $this->text_field(get_string('correct', 'question')); 246 } 247 return $question; 248 } 249 250 protected function parse_mc($qrec, $question) { 251 $question = $this->add_blank_combined_feedback($question); 252 $answer = 'choice-'.strtolower(trim($qrec['answer'][0]['#'])); 253 254 $choices = $qrec['choices'][0]['#']; 255 foreach ($choices as $key => $value) { 256 if (strpos(trim($key), 'choice-') !== false) { 257 258 $question->answer[] = $this->text_field(s($this->unxmlise($value[0]['#']))); 259 if (strcmp($key, $answer) == 0) { 260 $question->fraction[] = 1; 261 $question->feedback[] = $this->text_field(get_string('correct', 'question')); 262 } else { 263 $question->fraction[] = 0; 264 $question->feedback[] = $this->text_field(get_string('incorrect', 'question')); 265 } 266 } 267 } 268 return $question; 269 } 270 271 protected function parse_co($qrec, $question) { 272 $question->usecase = 0; 273 $answer = trim($this->unxmlise($qrec['answer'][0]['#'])); 274 $answer = strip_tags( $answer ); 275 $answers = explode("\n", $answer); 276 277 foreach ($answers as $key => $value) { 278 $value = trim($value); 279 if (strlen($value) > 0) { 280 $question->answer[] = $value; 281 $question->fraction[] = 1; 282 $question->feedback[] = $this->text_field(get_string('correct', 'question')); 283 } 284 } 285 $question->answer[] = '*'; 286 $question->fraction[] = 0; 287 $question->feedback[] = $this->text_field(get_string('incorrect', 'question')); 288 289 return $question; 290 } 291 292 protected function parse_es($qrec, $question) { 293 $feedback = trim($this->unxmlise($qrec['answer'][0]['#'])); 294 $question->graderinfo = $this->text_field($feedback); 295 $question->responsetemplate = $this->text_field(''); 296 $question->responserequired = 1; 297 $question->feedback = $feedback; 298 $question->responseformat = 'editor'; 299 $question->responsefieldlines = 15; 300 $question->attachments = 0; 301 $question->attachmentsrequired = 0; 302 $question->fraction = 0; 303 return $question; 304 } 305 306 protected function parse_nr($qrec, $question) { 307 $answer = trim($this->unxmlise($qrec['answer'][0]['#'])); 308 $answer = strip_tags( $answer ); 309 $answers = explode("\n", $answer); 310 311 foreach ($answers as $key => $value) { 312 $value = trim($value); 313 if (is_numeric($value)) { 314 $errormargin = 0; 315 $question->answer[] = $value; 316 $question->fraction[] = 1; 317 $question->feedback[] = $this->text_field(get_string('correct', 'question')); 318 $question->tolerance[] = $errormargin; 319 } 320 } 321 return $question; 322 } 323 324 } 325 // End class. 326 327
title
Description
Body
title
Description
Body
title
Description
Body
title
Body