From d3ab3ecf7f50317d8a0109a9f96e13d9273c298d Mon Sep 17 00:00:00 2001 From: Mathieu Loiseau <mathieu.loiseau@univ-grenoble-alpes.fr> Date: Tue, 25 Jan 2022 16:30:12 +0100 Subject: [PATCH] multi,truefalse --- XML_Moodle.py | 109 ++++++++++++++++++++++++++++++++++++++++++-------- utils.py | 17 ++++++-- 2 files changed, 106 insertions(+), 20 deletions(-) diff --git a/XML_Moodle.py b/XML_Moodle.py index eadbb07..f9ad0d4 100755 --- a/XML_Moodle.py +++ b/XML_Moodle.py @@ -11,15 +11,30 @@ class Quizz: def get_tree(self): return self.tree + def create_question(self, q, c): + if c not in self.questions.keys(): + self.questions[c] = [] + if q.attrib['type'] == "multichoice": + newQ = MCQ(q,c,len(self.questions[c])) + elif q.attrib['type'] == "shortanswer": + newQ = Question(q,c,len(self.questions[c])) + elif q.attrib['type'] == "truefalse": + newQ = TF(q,c,len(self.questions[c])) + elif q.attrib['type'] == "matching": + newQ = Question(q,c,len(self.questions[c])) + elif q.attrib['type'] == "ddimageortext": + newQ = Question(q,c,len(self.questions[c])) + else: + raise f"{q.attrib['type']} is not expected" + self.questions[c].append(newQ) + def parse(self): questions = self.tree.findall("question") for q in questions: if q.attrib["type"] == "category": c = q.find("category/text").text.replace("$course$/top/","").replace("/",":").replace("::","/") else: - if c not in self.questions.keys(): - self.questions[c] = [] - self.questions[c].append(Question(q,c,len(self.questions[c]))) + self.create_question(q, c) def __str__(self): res = "" @@ -33,23 +48,83 @@ class Question: self.q = mlang_2_multiling(strip_tags(xmlQ.find("questiontext/text").text)) self.category = c self.id = f"{c[c.rfind(':')+1:]}_{n}" + self.env = "questionmult" self.max = float(xmlQ.find("defaultgrade").text) def __str__(self): return """\\element{"""+self.category+"""}{ - \\begin{questionmult}{"""+self.id+"""}\\nbpoints{"""+score_2_str(self.max)+"""} - """+self.q+""" - \\begin{choices} - \\correctchoice{L'utilisation d'un traitement de texte en cours de langue.}\\bareme{b=0.25} - \\correctchoice{L'évaluation de l'interface d'un concordancier en vue de son utilisation en classe d'anglais.}\\bareme{b=0.15} - \\correctchoice{L'utilisation d'un glossaire en ligne sur l'informatique en cours de FLE.}\\bareme{b=0.15} - \\wrongchoice{L'utilisation d'un dictionnaire en cours d'anglais.}\\bareme{b=0,m=-0.25} - \\wrongchoice{La création d'un glossaire en ligne sur l'informatique.}\\bareme{b=0} - \\end{choices} - \\explain{La création d'un lexique ne relève pas intrinsèquement de l'ALAO, encore faut-il que son usage soit lié à l'apprentissage d'une langue.} - \\end{questionmult} -}\n\n""" + \\begin{"""+self.env+"""}{"""+self.id+"""}\\nbpoints{"""+score_2_str(self.max)+"""} + """+self.q+"\\end{"+self.env+"}" + +class Answer: + def __init__(self,t,b,max,fb): + self.status = float(b) > 0 + self.text = t + self.points = round(float(b)/(100*float(max)),3) + self.feedback = fb + + def __str__(self): + res = "\t\t\t" + if self.status: + res += "\\correctchoice{" + else: + res += "\\wrongchoice{" + res += self.text + res+="}" + if self.points >= 0: + res += "\\bareme{b="+str(self.points)+"}" + else: + res += "\\bareme{m="+str(self.points)+"}" + if self.feedback != None: + res += "\n\\explain{"+self.feedback+"}" + return res+"\n" + + +class MCQ(Question): + def __init__(self, xmlQ,c,n): + super().__init__(xmlQ,c,n) + self.choices = [] + self.__parseAnswers(xmlQ) + + def __parseAnswers(self, xmlQ): + self.shuffle = xmlQ.find("shuffleanswers").text == "true" + for a in xmlQ.findall("answer"): + fb = a.find("feedback/text").text + if fb != None: + fb = mlang_2_multiling(strip_tags(fb)) + self.choices.append(Answer(mlang_2_multiling(strip_tags(a.find("text").text)), a.attrib['fraction'], self.max, fb)) + + def __str__(self): + res = """\\element{"""+self.category+"""}{ + \\begin{"""+self.env+"""}{"""+self.id+"""}\\nbpoints{"""+score_2_str(self.max)+"""} + """+self.q+"\n\t\t\\begin{choices}" + if not self.shuffle: + res += "[o]" + res += "\n" + for c in self.choices: + res += str(c) + res += "\n\t\t\\end{choices}\n\t\\end{"+self.env+"}\n}\n\n" + return res + +class TF(MCQ): + def __init__(self, xmlQ,c,n): + super(MCQ, self).__init__(xmlQ,c,n) + self.choices = [] + self.env = "question" + self.shuffle = False + self.__parseAnswers(xmlQ) + + def __parseAnswers(self, xmlQ): + print("ok") + for a in xmlQ.findall("answer"): + fb = a.find("feedback/text").text + if fb != None: + fb = mlang_2_multiling(strip_tags(fb)) + if a.find("text").text == "true": + self.choices.append(Answer("\\multi{vrai}{true}", a.attrib['fraction'], self.max, fb)) + else: + self.choices.append(Answer("\\multi{faux}{false}", a.attrib['fraction'], self.max, fb)) if __name__ == "__main__": - # quizz = Quizz("quiz-GI-4-SID-S1-top-20201204-1620.xml") - quizz = Quizz("quiz-GI-4.xml") + quizz = Quizz("quiz-GI-4-SID-S1-top-20201204-1620.xml") + #quizz = Quizz("quiz-GI-4.xml") print(quizz) diff --git a/utils.py b/utils.py index 79dd3b5..0ca1236 100644 --- a/utils.py +++ b/utils.py @@ -1,14 +1,25 @@ #!/usr/bin/env python3 -from re import compile,sub +from re import compile,sub,escape + +def html_2_tex(text): + #https://code.activestate.com/recipes/81330-single-pass-multiple-replace/ + dict = {' ': '~', '>':'>', '<': '<'} + """ Replace in 'text' all occurences of any key in the given + dictionary by its corresponding value. Returns the new tring.""" + # Create a regular expression from the dictionary keys + regex = compile("(%s)" % "|".join(map(escape, dict.keys()))) + + # For each match, look-up corresponding value in dictionary + return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) def remove_moodle_cdata(txt): return txt.replace("<![CDATA[","").replace("]]>","") def strip_tags(txt): - return sub(compile('<.*?>'), '',remove_moodle_cdata(txt)) + return html_2_tex(sub(compile('<.*?>'), '',remove_moodle_cdata(txt))) def mlang_2_multiling(txt): - return sub(r"\{mlang en\}(.*?)\{mlang\}\{mlang other\}(.*?)\{mlang\}", r"\\multiling{\2}{\1}",txt) + return sub(r"\{mlang en\}(.*?)\{mlang\}((\{mlang other\})|(\{mlang fr\}))(.*?)\{mlang\}", r"\\multiling{\5}{\1}",txt) def score_2_str(v): if int(v)==float(v): -- GitLab