diff -Nuar standard_moodle/backup/moodle2/backup_qtype_plugin.class.php my_moodle/backup/moodle2/backup_qtype_plugin.class.php
--- standard_moodle/backup/moodle2/backup_qtype_plugin.class.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/backup/moodle2/backup_qtype_plugin.class.php	2011-03-14 09:03:01.000000000 +0300
@@ -241,7 +241,12 @@
 
         $extraanswerfields = $questiontype->extra_answer_fields();
         if (is_array($extraanswerfields)) {
-            // TODO backup extra answer table
+            $answerextensiontable = array_shift($extraanswerfields);
+            $answers = new backup_nested_element($pluginname . '_records');
+            $answer = new backup_nested_element($pluginname. '_record', array('id'), $extraanswerfields);
+            $pluginwrapper->add_child($answers);
+            $answers->add_child($answer);
+            $answer->set_source_table($answerextensiontable, array($questionidfield => backup::VAR_PARENTID));
         }
         return $plugin;
     }
diff -Nuar standard_moodle/backup/moodle2/restore_qtype_plugin.class.php my_moodle/backup/moodle2/restore_qtype_plugin.class.php
--- standard_moodle/backup/moodle2/restore_qtype_plugin.class.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/backup/moodle2/restore_qtype_plugin.class.php	2011-03-14 09:05:25.000000000 +0300
@@ -332,7 +332,9 @@
 
         $extraanswerfields = $questiontype->extra_answer_fields();
         if (is_array($extraanswerfields)) {
-            //TODO restore extra answer table
+            $elename = $pluginname . '_record';
+            $elepath = $this->get_pathfor("/{$pluginname}_records/{$pluginname}_record"); // we used get_recommended_name() so this works
+            $paths[] = new restore_path_element($elename, $elepath);
         }
 
         return $paths; // And we return the interesting paths
@@ -371,12 +373,52 @@
     }
 
     /**
+     *
+     */
+    public function process_extra_answer_fields(&$data){
+        global $DB;
+        global $QTYPES;
+        $pluginname = $this->pluginname;
+        $qtypeobj = $QTYPES[$pluginname];
+        $extraanswerffields = $qtypeobj->extra_answer_fields();
+        $extraanswertable = array_shift($extraanswerffields);
+        $questionfield = $qtypeobj->questionid_column_name();
+        $data = (object)$data;
+        $oldid = $data->id;
+
+        // Detect if the question is created or mapped
+        $oldquestionid   = $this->get_old_parentid('question');
+        $newquestionid   = $this->get_new_parentid('question');
+        $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
+
+        // If the question has been created by restore, we need to create its extra_answer_table record too
+        if ($questioncreated) {
+            $data->$questionfield = $newquestionid;
+            $data->answer = $this->get_mappingid('question_answer', $data->answer);
+            $this->remap_extra_answer_fields($data);
+            // Insert record
+            $newitemid = $DB->insert_record($extraanswertable, $data);
+            // Create mapping
+            $this->set_mapping($extraanswertable, $oldid, $newitemid);
+        } else {
+            // Nothing to remap if the question already existed
+        }
+    }
+
+    /**
      * remap ids in extra question table. reimplement this in your class
      */
     protected function remap_extra_question_fields(&$data) {
         return null;
     }
 
+    /**
+     * remap ids in extra answer table. reimplement this in your class
+     */
+    protected function remap_extra_answer_fields(&$data) {
+        return null;
+    }
+
     /**
      * Return the contents of the questions stuff that must be processed by the links decoder
      *
diff -Nuar standard_moodle/question/format/xml/format.php my_moodle/question/format/xml/format.php
--- standard_moodle/question/format/xml/format.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/question/format/xml/format.php	2011-03-14 09:03:01.000000000 +0300
@@ -494,6 +494,7 @@
 
     /**
      * import numerical type question
+     * @deprecated use qtype import_from_xml for numerical question
      * @param array question question array from xml tree
      * @return object question object
      */
@@ -853,9 +854,6 @@
             elseif ($question_type=='shortanswer') {
                 $qo = $this->import_shortanswer( $question );
             }
-            elseif ($question_type=='numerical') {
-                $qo = $this->import_numerical( $question );
-            }
             elseif ($question_type=='description') {
                 $qo = $this->import_description( $question );
             }
@@ -1193,56 +1191,6 @@
                 $expout .= "    </answer>\n";
             }
             break;
-        case NUMERICAL:
-            foreach ($question->options->answers as $answer) {
-                $tolerance = $answer->tolerance;
-                $percent = 100 * $answer->fraction;
-                $expout .= "<answer fraction=\"$percent\">\n";
-                // <text> tags are an added feature, old filed won't have them
-                $expout .= "    <text>{$answer->answer}</text>\n";
-                $expout .= "    <tolerance>$tolerance</tolerance>\n";
-                $feedbackformat = $this->get_format($answer->feedbackformat);
-                $expout .= "    <feedback format=\"$feedbackformat\">\n";
-                $expout .= $this->writetext($answer->feedback);
-                $expout .= $this->writefiles($answer->feedbackfiles);
-                $expout .= "    </feedback>\n";
-                // fraction tag is deprecated
-                // $expout .= "    <fraction>{$answer->fraction}</fraction>\n";
-                $expout .= "</answer>\n";
-            }
-
-            $units = $question->options->units;
-            if (count($units)) {
-                $expout .= "<units>\n";
-                foreach ($units as $unit) {
-                    $expout .= "  <unit>\n";
-                    $expout .= "    <multiplier>{$unit->multiplier}</multiplier>\n";
-                    $expout .= "    <unit_name>{$unit->unit}</unit_name>\n";
-                    $expout .= "  </unit>\n";
-                }
-                $expout .= "</units>\n";
-            }
-            if (isset($question->options->unitgradingtype)) {
-                $expout .= "    <unitgradingtype>{$question->options->unitgradingtype}</unitgradingtype>\n";
-            }
-            if (isset($question->options->unitpenalty)) {
-                $expout .= "    <unitpenalty>{$question->options->unitpenalty}</unitpenalty>\n";
-            }
-            if (isset($question->options->showunits)) {
-                $expout .= "    <showunits>{$question->options->showunits}</showunits>\n";
-            }
-            if (isset($question->options->unitsleft)) {
-                $expout .= "    <unitsleft>{$question->options->unitsleft}</unitsleft>\n";
-            }
-            if (!empty($question->options->instructionsformat)) {
-                $textformat = $this->get_format($question->options->instructionsformat);
-                $files = $fs->get_area_files($contextid, 'qtype_numerical', 'instruction', $question->id);
-                $expout .= "    <instructions format=\"$textformat\">\n";
-                $expout .= $this->writetext($question->options->instructions, 3);
-                $expout .= $this->writefiles($files);
-                $expout .= "    </instructions>\n";
-            }
-            break;
         case MATCH:
             foreach($question->options->subquestions as $subquestion) {
                 $files = $fs->get_area_files($contextid, 'qtype_match', 'subquestion', $subquestion->id);
diff -Nuar standard_moodle/question/type/edit_question_form.php my_moodle/question/type/edit_question_form.php
--- standard_moodle/question/type/edit_question_form.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/question/type/edit_question_form.php	2011-03-14 09:03:01.000000000 +0300
@@ -383,6 +383,37 @@
                 }
             }
         }
+
+        $extraanswerfields = $QTYPES[$question->qtype]->extra_answer_fields();
+        if (is_array($extraanswerfields) && !empty($question->options)) {
+            array_shift($extraanswerfields);
+            array_shift($extraanswerfields);
+            $answers = $question->options->answers;
+            if (count($answers)) {
+                $key = 0;
+                foreach ($answers as $answer){
+                    $draftid = file_get_submitted_draft_itemid("feedback[{$key}]");
+                    $question->{"answer[{$key}]"} = $answer->answer;
+                    $question->{"fraction[{$key}]"} = $answer->fraction;
+                    $question->{"feedback[{$key}]"} = array();
+                    $question->{"feedback[{$key}]"}['format'] = $answer->feedbackformat;
+                    $question->{"feedback[{$key}]"}['text'] = file_prepare_draft_area(
+                        $draftid,       // draftid
+                        $this->context->id,    // context
+                        'question',   // component
+                        'answerfeedback',             // filarea
+                        !empty($answer->id)?(int)$answer->id:null, // itemid
+                        $this->fileoptions,    // options
+                        $answer->feedback      // text
+                    );
+                    $question->{"feedback[{$key}]"}['itemid'] = $draftid;
+                    foreach ($extraanswerfields as $field) {
+                        $question->{"{$field}[{$key}]"} = $answer->$field;
+                    }
+                    $key++;
+                }
+            }
+        }
         // subclass adds data_preprocessing code here
         $question = $this->data_preprocessing($question);
         parent::set_data($question);
diff -Nuar standard_moodle/question/type/numerical/backup/moodle2/backup_qtype_numerical_plugin.class.php my_moodle/question/type/numerical/backup/moodle2/backup_qtype_numerical_plugin.class.php
--- standard_moodle/question/type/numerical/backup/moodle2/backup_qtype_numerical_plugin.class.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/question/type/numerical/backup/moodle2/backup_qtype_numerical_plugin.class.php	2011-03-14 09:03:01.000000000 +0300
@@ -33,18 +33,8 @@
      */
     protected function define_question_plugin_structure() {
 
-        // Define the virtual plugin element with the condition to fulfill
-        $plugin = $this->get_plugin_element(null, '../../qtype', 'numerical');
-
-        // Create one standard named plugin element (the visible container)
-        $pluginwrapper = new backup_nested_element($this->get_recommended_name());
-
-        // connect the visible container ASAP
-        $plugin->add_child($pluginwrapper);
-
-        // This qtype uses standard question_answers, add them here
-        // to the tree before any other information that will use them
-        $this->add_question_question_answers($pluginwrapper);
+        $plugin = parent::define_question_plugin_structure();
+        $pluginwrapper = $plugin->get_child($this->get_recommended_name());
 
         // This qtype uses standard numerical units, add them here
         $this->add_question_numerical_units($pluginwrapper);
@@ -52,20 +42,6 @@
         // This qtype uses standard numerical options, add them here
         $this->add_question_numerical_options($pluginwrapper);
 
-        // Now create the qtype own structures
-        $numericalrecords = new backup_nested_element('numerical_records');
-        $numericalrecord = new backup_nested_element('numerical_record', array('id'), array(
-            'answer', 'tolerance'));
-
-        // Now the own qtype tree
-        $pluginwrapper->add_child($numericalrecords);
-        $numericalrecords->add_child($numericalrecord);
-
-        // set source to populate the data
-        $numericalrecord->set_source_table('question_numerical', array('question' => backup::VAR_PARENTID));
-
-        // don't need to annotate ids nor files
-
         return $plugin;
     }
 
diff -Nuar standard_moodle/question/type/numerical/backup/moodle2/restore_qtype_numerical_plugin.class.php my_moodle/question/type/numerical/backup/moodle2/restore_qtype_numerical_plugin.class.php
--- standard_moodle/question/type/numerical/backup/moodle2/restore_qtype_numerical_plugin.class.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/question/type/numerical/backup/moodle2/restore_qtype_numerical_plugin.class.php	2011-03-14 09:03:01.000000000 +0300
@@ -34,50 +34,18 @@
      * Returns the paths to be handled by the plugin at question level
      */
     protected function define_question_plugin_structure() {
-
-        $paths = array();
-
-        // This qtype uses question_answers, add them
-        $this->add_question_question_answers($paths);
+        $paths = parent::define_question_plugin_structure();
 
         // This qtype uses question_numerical_options and question_numerical_units, add them
         $this->add_question_numerical_options($paths);
         $this->add_question_numerical_units($paths);
-
-        // Add own qtype stuff
-        $elename = 'numerical';
-        $elepath = $this->get_pathfor('/numerical_records/numerical_record'); // we used get_recommended_name() so this works
-        $paths[] = new restore_path_element($elename, $elepath);
-
-
         return $paths; // And we return the interesting paths
     }
 
     /**
      * Process the qtype/numerical element
      */
-    public function process_numerical($data) {
-        global $DB;
-
-        $data = (object)$data;
-        $oldid = $data->id;
-
-        // Detect if the question is created or mapped
-        $oldquestionid   = $this->get_old_parentid('question');
-        $newquestionid   = $this->get_new_parentid('question');
-        $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
-
-        // If the question has been created by restore, we need to create its question_numerical too
-        if ($questioncreated) {
-            // Adjust some columns
-            $data->question = $newquestionid;
-            $data->answer = $this->get_mappingid('question_answer', $data->answer);
-            // Insert record
-            $newitemid = $DB->insert_record('question_numerical', $data);
-            // Create mapping (not needed, no files nor childs nor states here)
-            //$this->set_mapping('question_numerical', $oldid, $newitemid);
-        } else {
-            // Nothing to remap if the question already existed
-        }
+    public function process_numerical_record($data) {
+        $this->process_extra_answer_fields($data);
     }
 }
diff -Nuar standard_moodle/question/type/numerical/edit_numerical_form.php my_moodle/question/type/numerical/edit_numerical_form.php
--- standard_moodle/question/type/numerical/edit_numerical_form.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/question/type/numerical/edit_numerical_form.php	2011-03-14 09:03:01.000000000 +0300
@@ -62,28 +62,6 @@
         global $QTYPES ;
         if (isset($question->options)){
             $answers = $question->options->answers;
-            if (count($answers)) {
-                $key = 0;
-                foreach ($answers as $answer){
-                    $draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
-                    $default_values['answer['.$key.']'] = $answer->answer;
-                    $default_values['fraction['.$key.']'] = $answer->fraction;
-                    $default_values['tolerance['.$key.']'] = $answer->tolerance;
-                    $default_values['feedback['.$key.']'] = array();
-                    $default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
-                    $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
-                        $draftid,       // draftid
-                        $this->context->id,    // context
-                        'question',   // component
-                        'answerfeedback',             // filarea
-                        !empty($answer->id)?(int)$answer->id:null, // itemid
-                        $this->fileoptions,    // options
-                        $answer->feedback      // text
-                    );
-                    $default_values['feedback['.$key.']']['itemid'] = $draftid;
-                    $key++;
-                }
-            }
             $QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
 
             $question = (object)((array)$question + $default_values);
diff -Nuar standard_moodle/question/type/numerical/questiontype.php my_moodle/question/type/numerical/questiontype.php
--- standard_moodle/question/type/numerical/questiontype.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/question/type/numerical/questiontype.php	2011-03-14 09:03:01.000000000 +0300
@@ -51,22 +51,21 @@
         return array('shortanswer');
     }
 
+    function extra_question_fields() {
+        return null;
+    }
+
+    function extra_answer_fields() {
+        return array('question_numerical', 'answer', 'tolerance');
+    }
+
     function get_question_options(&$question) {
         // Get the question answers and their respective tolerances
         // Note: question_numerical is an extension of the answer table rather than
         //       the question table as is usually the case for qtype
         //       specific tables.
         global $CFG, $DB, $OUTPUT;
-        if (!$question->options->answers = $DB->get_records_sql(
-                                "SELECT a.*, n.tolerance " .
-                                "FROM {question_answers} a, " .
-                                "     {question_numerical} n " .
-                                "WHERE a.question = ? " .
-                                "    AND   a.id = n.answer " .
-                                "ORDER BY a.id ASC", array($question->id))) {
-            echo $OUTPUT->notification('Error: Missing question answer for numerical question ' . $question->id . '!');
-            return false;
-        }
+        parent::get_question_options($question);
         $this->get_numerical_units($question);
         //get_numerical_options() need to know if there are units
         // to set correctly default values
@@ -145,92 +144,19 @@
      * Save the units and the answers associated with this question.
      */
     function save_question_options($question) {
-        global $DB;
-        $context = $question->context;
-
-        // Get old versions of the objects
-        $oldanswers = $DB->get_records('question_answers',
-                array('question' => $question->id), 'id ASC');
-        $oldoptions = $DB->get_records('question_numerical',
-                array('question' => $question->id), 'answer ASC');
-
         // Save the units.
         $result = $this->save_numerical_units($question);
         if (isset($result->error)) {
             return $result;
         } else {
-            $units = $result->units;
-        }
-
-        // Insert all the new answers
-        foreach ($question->answer as $key => $answerdata) {
-            // Check for, and ingore, completely blank answer from the form.
-            if (trim($answerdata) == '' && $question->fraction[$key] == 0 &&
-                    html_is_blank($question->feedback[$key]['text'])) {
-                continue;
-            }
-
-            // Update an existing answer if possible.
-            $answer = array_shift($oldanswers);
-            if (!$answer) {
-                $answer = new stdClass();
-                $answer->question = $question->id;
-                $answer->answer = '';
-                $answer->feedback = '';
-                $answer->id = $DB->insert_record('question_answers', $answer);
-            }
-
-            if (trim($answerdata) === '*') {
-                $answer->answer = '*';
-            } else {
-                $answer->answer = $this->apply_unit($answerdata, $units);
-                if ($answer->answer === false) {
-                    $result->notice = get_string('invalidnumericanswer', 'quiz');
-                }
-            }
-            $answer->fraction = $question->fraction[$key];
-            $answer->feedback = $this->import_or_save_files($question->feedback[$key],
-                    $context, 'question', 'answerfeedback', $answer->id);
-            $answer->feedbackformat = $question->feedback[$key]['format'];
-            $DB->update_record('question_answers', $answer);
-
-            // Set up the options object
-            if (!$options = array_shift($oldoptions)) {
-                $options = new stdClass();
-            }
-            $options->question = $question->id;
-            $options->answer   = $answer->id;
-            if (trim($question->tolerance[$key]) == '') {
-                $options->tolerance = '';
-            } else {
-                $options->tolerance = $this->apply_unit($question->tolerance[$key], $units);
-                if ($options->tolerance === false) {
-                    $result->notice = get_string('invalidnumerictolerance', 'quiz');
-                }
-            }
-            if (isset($options->id)) {
-                $DB->update_record('question_numerical', $options);
-            } else {
-                $DB->insert_record('question_numerical', $options);
-            }
-        }
-
-        // Delete any left over old answer records.
-        $fs = get_file_storage();
-        foreach($oldanswers as $oldanswer) {
-            $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id);
-            $DB->delete_records('question_answers', array('id' => $oldanswer->id));
-        }
-        foreach($oldoptions as $oldoption) {
-            $DB->delete_records('question_numerical', array('id' => $oldoption->id));
+            $question->units = $result->units;
         }
-
-        $result = $this->save_numerical_options($question);
-        if (!empty($result->error) || !empty($result->notice)) {
-            return $result;
+        $result = parent::save_question_options($question);
+        $result0 = $this->save_numerical_options($question);
+        if (!empty($result0->error) || !empty($result0->notice)) {
+            $result = $result0;
         }
-
-        return true;
+        return $result;
     }
 
     /**
@@ -410,7 +336,6 @@
 
     function delete_question($questionid, $contextid) {
         global $DB;
-        $DB->delete_records('question_numerical', array('question' => $questionid));
         $DB->delete_records('question_numerical_options', array('question' => $questionid));
         $DB->delete_records('question_numerical_units', array('question' => $questionid));
 
@@ -1374,6 +1299,111 @@
                     $filearea, $args);
         }
     }
+
+    function import_from_xml ($data, $question, $format, $extra = null) {
+        $qo = parent::import_from_xml($data, $question, $format, $extra);
+        // Get numerical units
+        $qo->unit = array();
+        $units = $format->getpath($data, array('#','units',0,'#','unit'), array() );
+        if (!empty($units)) {
+            $qo->multiplier = array();
+            foreach ($units as $unit) {
+                $qo->multiplier[] = $format->getpath( $unit, array('#','multiplier',0,'#'), 1 );
+                $qo->unit[] = $format->getpath( $unit, array('#','unit_name',0,'#'), '', true );
+            }
+        }
+        // Get numerical options
+        $qo->unitgradingtype = $format->getpath( $data, array('#','unitgradingtype',0,'#'), 0 );
+        $qo->unitpenalty = $format->getpath( $data, array('#','unitpenalty',0,'#'), 0 );
+        $qo->showunits = $format->getpath( $data, array('#','showunits',0,'#'), 0 );
+        $qo->unitsleft = $format->getpath( $data, array('#','unitsleft',0,'#'), 0 );
+        $qo->instructions['text'] = '';
+        $qo->instructions['format'] = FORMAT_HTML;
+        $instructions = $format->getpath($data, array('#', 'instructions'), array());
+        if (!empty($instructions)) {
+            $qo->instructions = array();
+            $qo->instructions['text'] = $format->getpath($instructions,
+                    array('0', '#', 'text', '0', '#'), '', true);
+            $qo->instructions['format'] = $format->trans_format($format->getpath($instructions,
+                    array('0', '@', 'format'), 'moodle_auto_format'));
+            $files = $format->getpath($instructions, array('0', '#', 'file'), array());
+            $qo->instructions['files'] = array();
+            foreach ($files as $file) {
+                $filedata = new stdclass;
+                $filedata->content = $file['#'];
+                $filedata->encoding = $file['@']['encoding'];
+                $filedata->name = $file['@']['name'];
+                $qo->instructions['files'][]= $filedata;
+            }
+        }
+        return $qo;
+    }
+
+    function export_to_xml ($question, $format, $extra = null) {
+        $expout = parent::export_to_xml($question, $format, $extra);
+        $fs = get_file_storage();
+        if (isset($question->options->units)) {
+            $units = $question->options->units;
+            if (count($units)) {
+                $expout .= "<units>\n";
+                foreach ($units as $unit) {
+                    $expout .= "  <unit>\n";
+                    $expout .= "    <multiplier>{$unit->multiplier}</multiplier>\n";
+                    $expout .= "    <unit_name>{$unit->unit}</unit_name>\n";
+                    $expout .= "  </unit>\n";
+                }
+                $expout .= "</units>\n";
+            }
+        }
+        if (isset($question->options->unitgradingtype)) {
+            $expout .= "    <unitgradingtype>{$question->options->unitgradingtype}</unitgradingtype>\n";
+        }
+        if (isset($question->options->unitpenalty)) {
+            $expout .= "    <unitpenalty>{$question->options->unitpenalty}</unitpenalty>\n";
+        }
+        if (isset($question->options->showunits)) {
+            $expout .= "    <showunits>{$question->options->showunits}</showunits>\n";
+        }
+        if (isset($question->options->unitsleft)) {
+            $expout .= "    <unitsleft>{$question->options->unitsleft}</unitsleft>\n";
+        }
+        if (!empty($question->options->instructionsformat)) {
+            $textformat = $format->get_format($question->options->instructionsformat);
+            $files = $fs->get_area_files($question->contextid, 'qtype_' . $question->qtype, 'instruction', $question->id);
+            $expout .= "    <instructions format=\"$textformat\">\n";
+            $expout .= $format->writetext($question->options->instructions, 3);
+            $expout .= $format->writefiles($files);
+            $expout .= "    </instructions>\n";
+        }
+        return $expout;
+    }
+
+    function prepare_question(&$question) {
+        return null;
+    }
+
+    function prepare_answers(&$question) {
+        $res = null;
+        foreach ($question->answer as $key => $answerdata) {
+            if (trim($answerdata) === '*') {
+                $question->answer[$key] = '*';
+            } else {
+                $question->answer[$key] = $this->apply_unit($answerdata, $question->units);
+                if ($question->answer[$key] === false) {
+                    $res = get_string('invalidnumericanswer', 'quiz');
+                }
+            }
+            if (trim($question->tolerance[$key]) == '') {
+                $question->tolerance[$key] = '';
+            } else {
+                $question->tolerance[$key] = $this->apply_unit($question->tolerance[$key], $question->units);
+                if ($question->tolerance[$key] === false) {
+                    $res = get_string('invalidnumerictolerance', 'quiz');
+                }
+            }
+        }
+        return $res;
+    }
 }
 
 // INITIATION - Without this line the question type is not in use.
diff -Nuar standard_moodle/question/type/questiontype.php my_moodle/question/type/questiontype.php
--- standard_moodle/question/type/questiontype.php	2011-03-14 09:02:22.000000000 +0300
+++ my_moodle/question/type/questiontype.php	2011-03-14 09:03:01.000000000 +0300
@@ -181,7 +181,8 @@
     /**
      * If your question type has a table that extends the question_answers table,
      * make this method return an array wherer the first element is the table name,
-     * and the subsequent entries are the column names (apart from id and answerid).
+     * second element is answerid field name and the subsequent entries are
+     * the column names (apart from id, questionid and answerid).
      *
      * @return mixed array as above, or null to tell the base class to do nothing.
      */
@@ -412,7 +413,91 @@
     function save_question_options($question) {
         global $DB;
         $result = new stdClass;
-        $result->notice = $this->prepare_question($question);
+        $result->notice = $this->prepare_answers($question);
+        if ($this->use_answers()) {
+            $context = $question->context;
+            $oldanswers = $DB->get_records('question_answers',
+                    array('question' => $question->id), 'id ASC');
+            $extraanswerfields = $this->extra_answer_fields();
+
+            if (is_array($extraanswerfields)) {
+                $questionidfield = $this->questionid_column_name();
+                $extraanswertable = array_shift($extraanswerfields);
+                $answeridfield = array_shift($extraanswerfields);
+                $oldanswerextrafieldsvalues = $DB->get_records($extraanswertable,
+                        array($questionidfield => $question->id), $answeridfield. ' ASC');
+            }
+            // Insert all the new answers
+            $maxfraction = -1;
+            foreach ($question->answer as $key => $answerdata) {
+                // Check for, and ignore, completely blank answer from the form.
+                if (trim($answerdata) == '' && $question->fraction[$key] == 0 &&
+                        html_is_blank($question->feedback[$key]['text'])) {
+                    continue;
+                }
+
+                // Update an existing answer if possible.
+                $answer = array_shift($oldanswers);
+                if (!$answer) {
+                    $answer = new stdClass();
+                    $answer->question = $question->id;
+                    $answer->answer = '';
+                    $answer->feedback = '';
+                    $answer->id = $DB->insert_record('question_answers', $answer);
+                }
+                $answer->answer = $answerdata;
+                $answer->fraction = $question->fraction[$key];
+                $answer->feedback = $this->import_or_save_files($question->feedback[$key],
+                        $context, 'question', 'answerfeedback', $answer->id);
+                $answer->feedbackformat = $question->feedback[$key]['format'];
+                $DB->update_record('question_answers', $answer);
+
+                if ($question->fraction[$key] > $maxfraction) {
+                    $maxfraction = $question->fraction[$key];
+                }
+
+                if (is_array($extraanswerfields)) {
+                    // Set up the answer extras object
+                    if (!$answerextrafieldsvalue = array_shift($oldanswerextrafieldsvalues)) {
+                        $answerextrafieldsvalue = new stdClass();
+                    }
+                    $answerextrafieldsvalue->$questionidfield = $question->id;
+                    $answerextrafieldsvalue->$answeridfield   = $answer->id;
+                    foreach ($extraanswerfields as $field) {
+                        if (!isset($question->{$field}[$key])) {
+                            $result = new stdClass;
+                            $result->error = "No data for field {$field} when saving {$this->name()} " .
+                                             "question id {$question->id} answer id {$answer->id}";
+                            return $result;
+                        }
+                        $answerextrafieldsvalue->$field = $question->{$field}[$key];
+                    }
+                    if (isset($answerextrafieldsvalue->id)) {
+                        $DB->update_record($extraanswertable, $answerextrafieldsvalue);
+                    } else {
+                        $DB->insert_record($extraanswertable, $answerextrafieldsvalue);
+                    }
+                }
+            }
+
+            // Delete any left over old answer records.
+            $fs = get_file_storage();
+            foreach($oldanswers as $oldanswer) {
+                $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id);
+                $DB->delete_records('question_answers', array('id' => $oldanswer->id));
+            }
+            if (is_array($extraanswerfields)) {
+                // Delete any left over old answer extras.
+                foreach($oldanswerextrafieldsvalues as $oldanswerextrafieldsvaluesfieldsvalue) {
+                    $DB->delete_records($extraanswertable, array('id' => $oldanswerextrafieldsvaluesfieldsvalue->id));
+                }
+            }
+        }
+
+        $prepare_result = $this->prepare_question($question);
+        if (!empty($prepare_result)) {
+            $result->notice = $prepare_result;
+        }
         $extraquestionfields = $this->extra_question_fields();
 
         if (is_array($extraquestionfields)) {
@@ -448,11 +533,15 @@
                 return $result;
             }
         }
+        // Perform sanity checks on fractional grades
+        if ($maxfraction != 1) {
+            $result->notice = get_string('fractionsnomax', 'quiz', $maxfraction * 100);
+        }
+        if (!empty($result->notice) || !empty($result->error)) {
+            return $result;
+        }
 
-        $extra_answer_fields = $this->extra_answer_fields();
-        // TODO save the answers, with any extra data.
-
-        return null;
+        return true;
     }
 
     /**
@@ -489,16 +578,18 @@
             }
         }
 
-        $extra_answer_fields = $this->extra_answer_fields();
-        if (is_array($extra_answer_fields)) {
-            $answer_extension_table = array_shift($extra_answer_fields);
-            $question->options->answers = $DB->get_records_sql("
-                    SELECT qa.*, qax." . implode(', qax.', $extra_answer_fields) . "
-                    FROM {question_answers} qa, {$answer_extension_table} qax
-                    WHERE qa.questionid = ? AND qax.answerid = qa.id", array($question->id));
+        $extraanswerfields = $this->extra_answer_fields();
+        if (is_array($extraanswerfields)) {
+            $answerextensiontable = array_shift($extraanswerfields);
+            $answeridfield = array_shift($extraanswerfields);
+            $questionidfield = $this->questionid_column_name();
+            $question->options->answers = $DB->get_records_sql(
+                    'SELECT qa.*, qax.' . implode(', qax.', $extraanswerfields) .
+                    " FROM {question_answers} qa, {{$answerextensiontable}} qax" .
+                    " WHERE qa.{$questionidfield} = ? AND qax.{$answeridfield} = qa.id", array($question->id));
             if (!$question->options->answers) {
-                echo $OUTPUT->notification("Failed to load question answers from the table $answer_extension_table for questionid " .
-                        $question->id);
+                echo $OUTPUT->notification('Failed to load question answers from the table ' .
+                                           "{$answerextensiontable} for questionid {$question->id}");
                 return false;
             }
         } else {
@@ -538,11 +629,12 @@
                     array($this->questionid_column_name() => $questionid));
         }
 
-        $extra_answer_fields = $this->extra_answer_fields();
-        if (is_array($extra_answer_fields)) {
-            $answer_extension_table = array_shift($extra_answer_fields);
-            $DB->delete_records_select($answer_extension_table,
-                "answerid IN (SELECT qa.id FROM {question_answers} qa WHERE qa.question = ?)", array($questionid));
+        $extraanswerfields = $this->extra_answer_fields();
+        if (is_array($extraanswerfields)) {
+            $answerextensiontable = array_shift($extraanswerfields);
+            $answeridfield = array_shift($extraanswerfields);
+            $DB->delete_records_select($answerextensiontable,
+                "{$answeridfield} IN (SELECT qa.id FROM {question_answers} qa WHERE qa.question = ?)", array($questionid));
         }
 
         $DB->delete_records('question_answers', array('question' => $questionid));
@@ -1585,6 +1677,7 @@
                 }
             }
         }
+        // Get answers
         if ($this->use_answers()) {
             // run through the answers
             $answers = $data['#']['answer'];
@@ -1599,7 +1692,16 @@
             }
             $extraasnwersfields = $this->extra_answer_fields();
             if (is_array($extraasnwersfields)) {
-                //TODO import the answers, with any extra data.
+                //skip table name and answerid field
+                array_shift($extraasnwersfields);
+                array_shift($extraasnwersfields);
+                foreach ($extraasnwersfields as $field) {
+                    $valuearray = array();
+                    foreach ($answers as $answer) {
+                        $valuearray[] = $format->getpath($answer, array('#', $field, 0, '#'), '');
+                    }
+                    $qo->$field = $valuearray;
+                }
             }
         }
         return $qo;
@@ -1634,7 +1736,12 @@
             }
         }
         if ($this->use_answers()) {
-            $extraasnwersfields = $this->extra_answer_fields();
+            $extraanswersfields = $this->extra_answer_fields();
+            if (is_array($extraanswersfields)) {
+                // skip table name and answerid field
+                array_shift($extraanswersfields);
+                array_shift($extraanswersfields);
+            }
             foreach ($question->options->answers as $answer) {
                 $percent = 100 * $answer->fraction;
                 $expout .= "    <answer fraction=\"$percent\">\n";
@@ -1644,8 +1751,10 @@
                 $expout .= $format->writetext($answer->feedback, 4, false);
                 $expout .= $format->writefiles($answer->feedbackfiles);
                 $expout .= "      </feedback>\n";
-                if (is_array($extraasnwersfields)) {
-                    //TODO export answers with any extra data
+                if (is_array($extraanswersfields)) {
+                    foreach ($extraanswersfields as $field) {
+                        $expout .= "      <{$field}>{$answer->$field}</{$field}>\n";
+                    }
                 }
                 $expout .= "    </answer>\n";
             }
@@ -1822,6 +1931,15 @@
         return null;
     }
 
+    /**
+     * Prepare answer fields for writing to DB
+     * reimplement in your class if answer data must be chaged before writing to DB
+     * @return null if ok, else - notice message
+     */
+    function prepare_answers(&$question) {
+        return null;
+    }
+
     /**
      * Transform extra options
      */
diff -Nuar standard_moodle/question/type/shortanswer/questiontype.php my_moodle/question/type/shortanswer/questiontype.php
--- standard_moodle/question/type/shortanswer/questiontype.php	2011-03-14 08:53:14.000000000 +0300
+++ my_moodle/question/type/shortanswer/questiontype.php	2011-03-14 09:03:01.000000000 +0300
@@ -59,71 +59,6 @@
         $this->delete_files_in_answers($questionid, $contextid);
     }
 
-    function save_question_options($question) {
-        global $DB;
-        $result = new stdClass;
-
-        $context = $question->context;
-
-        $oldanswers = $DB->get_records('question_answers',
-                array('question' => $question->id), 'id ASC');
-
-        // Insert all the new answers
-        $answers = array();
-        $maxfraction = -1;
-        foreach ($question->answer as $key => $answerdata) {
-            // Check for, and ignore, completely blank answer from the form.
-            if (trim($answerdata) == '' && $question->fraction[$key] == 0 &&
-                    html_is_blank($question->feedback[$key]['text'])) {
-                continue;
-            }
-
-            // Update an existing answer if possible.
-            $answer = array_shift($oldanswers);
-            if (!$answer) {
-                $answer = new stdClass();
-                $answer->question = $question->id;
-                $answer->answer = '';
-                $answer->feedback = '';
-                $answer->id = $DB->insert_record('question_answers', $answer);
-            }
-
-            $answer->answer   = trim($answerdata);
-            $answer->fraction = $question->fraction[$key];
-            $answer->feedback = $this->import_or_save_files($question->feedback[$key],
-                    $context, 'question', 'answerfeedback', $answer->id);
-            $answer->feedbackformat = $question->feedback[$key]['format'];
-            $DB->update_record('question_answers', $answer);
-
-            $answers[] = $answer->id;
-            if ($question->fraction[$key] > $maxfraction) {
-                $maxfraction = $question->fraction[$key];
-            }
-        }
-
-        // Delete any left over old answer records.
-        $fs = get_file_storage();
-        foreach($oldanswers as $oldanswer) {
-            $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id);
-            $DB->delete_records('question_answers', array('id' => $oldanswer->id));
-        }
-
-        $question->answers = implode(',', $answers);
-        $parentresult = parent::save_question_options($question);
-        if ($parentresult !== null) {
-            // Parent function returns null if all is OK
-            return $parentresult;
-        }
-
-        // Perform sanity checks on fractional grades
-        if ($maxfraction != 1) {
-            $result->noticeyesno = get_string('fractionsnomax', 'quiz', $maxfraction * 100);
-            return $result;
-        }
-
-        return true;
-    }
-
     function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
         global $CFG;
         $context = $this->get_context_by_category_id($question->category);
@@ -409,6 +344,12 @@
         }
     }
 
+    function prepare_answers(&$question) {
+        foreach ($question->answer as $key => $answerdata) {
+            $question->answer[$key] = trim($answerdata);
+        }
+    }
+
     function prepare_question(&$question) {
         global $DB;
         $answers = $DB->get_records('question_answers',
