-
Notifications
You must be signed in to change notification settings - Fork 5
Quiz Manager: Question Collection
Abbreviations: MXML(Moodle XML)
HR(Human Readable) This solution is used for parsing questions exported in the MXML format to a Human Readable format and a JSON file.
There are 2 shell scripts that can be used to generate the HR and JSON outputs.
- ./generate-HR.sh uses MXML files as input and generates HR files.
- ./generate-JSON.sh uses HR files as input and generates JSON files
Both of these scripts have multiple options and their usage will be explained further in this document.
The contents of both HR and JSON outputs are determined by the structure.json
file which will be explained below.
This file acts like a config file and describes an individual question (JSON Object), it can be modified if a user wishes to add more tags (an example will be given shortly).
The most basic structure.json file containing only the mandatory fields is the following:
{
"statement":"",
"tags" : [
],
"answers": [
{
"statement":"",
"correct":false,
"grade":0.0
}
],
"correctAnswersNo":0
}
The tags
object is a list that will contain all other tags that have been added by running the ./generate-HR.sh
script and are not specified in the structure.json
file.
In the JSON output file, tags
has the following format:
"tags": [
{
"key": "ExtraTag1_Name",
"values": [
"Tag_Value1",
"Tag_Value2"
]
}
]
For the rest of the examples in this document, we will be using the following file:
{
"createdOn":"",
"lastUsed":"",
"difficulty":0,
"statement":"",
"tags" : [
],
"answers": [
{
"statement":"",
"correct":false,
"grade":0.0
}
],
"correctAnswersNo":0
}
tag1:value1;tag2:value2;...;tagN:valueN;
Statement
+ Correct Answer
- Wrong Answer
Line by line explanations of the above format
tag1:value1;tag2:value2;...;tagN:valueN;
The first line of a question is the tagline. Here all tags and their values are stored.
The type of each tag is known from the structure.json
file.
All tags that are not found in the structure.json
file will be added to the tags
field, and all values will be added to a list of strings.
Statement
This is the statement of a question and it will be added as a string to the "statement"
field.
Multiline statements are supported.
+ Correct Answer
All correct answers are marked with a '+' character on the first position of the line.
When a correct answer is found "correctAnswersNo"
is incremented by 1 and the answer's "correct"
field is set to true
After all answers have been read, each correct answers' "grade"
== 1/"correctAnswersNo"
- Wrong Answer
All wrong answers are marked with a '-' character on the first position of the line.
For each wrong answer "grade" == -0.5
Multiline answers are supported
More information about ./generate-HR.sh
options can be found here
As mentioned above ./generate-HR.sh
parses MXML files to the HR format described above.
For this demo we have the following input file exported from Moodle:
<?xml version="1.0" encoding="UTF-8"?>
<quiz>
<!-- question: DEMO_QUESTION -->
<question type="multichoice">
<name>
<text>Test Question</text>
</name>
<questiontext format="html">
<text>Test Question Statement?</text>
</questiontext>
<generalfeedback format="html">
<text></text>
</generalfeedback>
<defaultgrade>1.0000000</defaultgrade>
<penalty>0.3333333</penalty>
<hidden>0</hidden>
<idnumber></idnumber>
<single>true</single>
<shuffleanswers>true</shuffleanswers>
<answernumbering>abc</answernumbering>
<correctfeedback format="html">
<text></text>
</correctfeedback>
<partiallycorrectfeedback format="html">
<text></text>
</partiallycorrectfeedback>
<incorrectfeedback format="html">
<text></text>
</incorrectfeedback>
<answer fraction="100" format="html">
<text>Answer 1</text>
<feedback format="html">
<text></text>
</feedback>
</answer>
<answer fraction="-50" format="html">
<text>Answer 2</text>
<feedback format="html">
<text></text>
</feedback>
</answer>
<answer fraction="-50" format="html">
<text>Answer 3</text>
<feedback format="html">
<text></text>
</feedback>
</answer>
<answer fraction="100" format="html">
<text>Answer 4</text>
<feedback format="html">
<text></text>
</feedback>
</answer>
<answer fraction="100" format="html">
<text>Answer 5</text>
<feedback format="html">
<text></text>
</feedback>
</answer>
</question>
</quiz>
Running the following script:
./generate-HR.sh -e topics,author,reviewed_by -u GC -t -c -y
-e topics,author,reviewed_by
This option will add the following extra tags: topics, author, reviewed_by
-u GC
This will autocomplete the "reviewed_by" tag with "GC"
-t
This will use the topic dictionary to automatically complete the appropriate topics for the question
The autotopic dictionary we will be using for this demo is:
topicDict = {}
topicDict["Topic1"] = ["Test", "Dummy"]
topicDict["Topic2"] = ["Question"]
topicDict["Topic3"] = ["Florin", "Salam"]
topicList = list(topicDict.keys())
The autotopic component of the Quiz Collection solution works by matching individual words from the question's statement and its correct answers to words related to a topic. In this demo the word "Florin" and "Salam" are related to the "Topic3" topic. In a real application we could see the words "passwd", "chmod" and "chown" relating to the "users" topic.
For a future feature, a way to generate this topic dictionary would be to feed relevant pieces of text to a script and generate a word cloud, with the most frequent terms being used for the dictionary.
! Warning
This automatic assignment of the topics does not work 100% of the time and some manual review is still needed
-c
Clean any old HR files
-y
If the filename contains a valid year number and the -y
option is passed to the script, the "createdOn", "lastUsed" tags will be autocompleted with that year as we'll see in the output below.
createdOn:2019-01-01;lastUsed:2019-01-01;difficulty:0;topics:Topic1,Topic2;author:n/a;reviewed_by:GC;
Test Question Statement?
+ Answer 1
- Answer 2
- Answer 3
+ Answer 4
+ Answer 5
After running the script this is the expected output file.
Notice the following:
-
difficulty
has it's default value set to0
, same as in the structure file. If we wanted the default value to be6
we could change the structure file like this:
"difficulty":6
- Since automatic topic assignment was enabled (
-t
), the script found the word "Test" which relates to the topic "Topic1" and the word "Question" which relates to the topic "Topic2" but since neither "Florin" or "Salam" was found, the topics tag has the following values:
topics:Topic1,Topic2
All that is left to do now is to review the question, make any changes as needed, and run the next script which will generate the JSON file.
More information about ./generate-JSON.sh
options can be found here
With HR_AT_0.hr
as our input we can run:
./generate-JSON.sh
The script will go line by line and build each JSON object
Building the tagline
The script will begin by reading a single line which will contain all the tags and their values
The line is split with ';' as a delimiter
The resulting list of strings is further split into key : value pairs
Building the statement
After reading the question's tagline next line is considered to be the first line of the statement.
The script will append all the strings on the next lines until a line with a '+' or '-' character on its first position is met (That means the script found the first answer).
The file pointer resets it's position to the one it had before reading the first line of the first answer.
Building the `answer` list
After reading the question's statement, the script will read the first answer statement until the next answer is found ('+' or '-' as the first character of the newly read line) or until the read line contains only a newline '\n' (This means that a new question is coming up and all answers of the current question have been read).
In the end the result should be the following JSON file:
[
{
"createdOn": "2019-01-01T00:00:00",
"lastUsed": "2019-01-01T00:00:00",
"difficulty": 0,
"statement": "Test Question Statement?\n",
"tags": [
{
"key": "topics",
"values": [
"Topic1",
"Topic2"
]
},
{
"key": "author",
"values": [
"n/a"
]
},
{
"key": "reviewed_by",
"values": [
"GC"
]
}
],
"answers": [
[
{
"statement": "Answer 1\n",
"correct": true,
"grade": 0.3333333333333333
},
{
"statement": "Answer 2\n",
"correct": false,
"grade": -0.5
},
{
"statement": "Answer 3\n",
"correct": false,
"grade": -0.5
},
{
"statement": "Answer 4\n",
"correct": true,
"grade": 0.3333333333333333
},
{
"statement": "Answer 5\n",
"correct": true,
"grade": 0.3333333333333333
}
]
],
"correctAnswersNo": 3
}
]