diff --git a/question/format/xml/format.php b/question/format/xml/format.php
index b2b71ffd1e5..0e63bdf0471 100644
--- a/question/format/xml/format.php
+++ b/question/format/xml/format.php
@@ -1196,6 +1196,8 @@ class qformat_xml extends qformat_default {
// Check question type.
$questiontype = $this->get_qtype($question->qtype);
+ $idnumber = htmlspecialchars($question->idnumber);
+
// Categories are a special case.
if ($question->qtype == 'category') {
$categorypath = $this->writetext($question->category);
@@ -1208,7 +1210,7 @@ class qformat_xml extends qformat_default {
$expout .= " \n";
$expout .= " {$categoryinfo}";
$expout .= " \n";
- $expout .= " {$question->idnumber}\n";
+ $expout .= " {$idnumber}\n";
$expout .= " \n";
return $expout;
}
@@ -1232,7 +1234,7 @@ class qformat_xml extends qformat_default {
}
$expout .= " {$question->penalty}\n";
$expout .= " {$question->hidden}\n";
- $expout .= " {$question->idnumber}\n";
+ $expout .= " {$idnumber}\n";
// The rest of the output depends on question type.
switch($question->qtype) {
diff --git a/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml b/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml
new file mode 100644
index 00000000000..cc1d37676e9
--- /dev/null
+++ b/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+ $course$/Alpha
+
+
+ This is Alpha category for test
+
+ The inequalities < & >
+
+
+
+
+
+ Alpha Question
+
+
+ Testing Alpha Question
]]>
+
+
+
+
+ 1.0000000
+ 1.0000000
+ 0
+ T & F
+
+ true
+
+
+
+
+
+ false
+
+
+
+
+
+
+
diff --git a/question/format/xml/tests/qformat_xml_import_export_test.php b/question/format/xml/tests/qformat_xml_import_export_test.php
index 4926bea1040..ebd9fcdc4e6 100644
--- a/question/format/xml/tests/qformat_xml_import_export_test.php
+++ b/question/format/xml/tests/qformat_xml_import_export_test.php
@@ -426,6 +426,44 @@ class qformat_xml_import_export_test extends advanced_testcase {
$this->assert_same_xml($expectedxml, $qformat->exportprocess());
}
+ /**
+ * Simple check for exporting a category.
+ */
+ public function test_export_category_with_special_chars() {
+ $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
+ $this->resetAfterTest(true);
+ $course = $this->getDataGenerator()->create_course();
+ $this->setAdminUser();
+ // Note while this loads $qformat with all the 'right' data from the xml file,
+ // the call to setCategory, followed by exportprocess will actually only export data
+ // from the database (created by the generator).
+ $qformat = $this->create_qformat('export_category.xml', $course);
+
+ $category = $generator->create_question_category([
+ 'name' => 'Alpha',
+ 'contextid' => '2',
+ 'info' => 'This is Alpha category for test',
+ 'infoformat' => '0',
+ 'idnumber' => 'The inequalities < & >',
+ 'stamp' => make_unique_id_code(),
+ 'parent' => '0',
+ 'sortorder' => '999']);
+ $generator->create_question('truefalse', null, [
+ 'category' => $category->id,
+ 'name' => 'Alpha Question',
+ 'questiontext' => ['format' => '1', 'text' => 'Testing Alpha Question
'],
+ 'generalfeedback' => ['format' => '1', 'text' => ''],
+ 'idnumber' => 'T & F',
+ 'correctanswer' => '1',
+ 'feedbacktrue' => ['format' => '1', 'text' => ''],
+ 'feedbackfalse' => ['format' => '1', 'text' => ''],
+ 'penalty' => '1']);
+ $qformat->setCategory($category);
+
+ $expectedxml = file_get_contents(__DIR__ . '/fixtures/html_chars_in_idnumbers.xml');
+ $this->assert_same_xml($expectedxml, $qformat->exportprocess());
+ }
+
/**
* Test that bad multianswer questions are not imported.
*/