diff --git a/XML_Moodle.py b/XML_Moodle.py index eadbb07991871eaff74bbc2efddd9f5c34d52f4c..f9ad0d49f1f19b946bc4fd77614d41b583a97586 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 79dd3b517e7d114b6399f7f322c31d04b6eca745..0ca123697dcbcffe9e3a03da78d58ee02576dd5c 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):