diff --git a/.gitignore b/.gitignore index c4b1d94abee088febd82ef42d7e2a5e5aaa5f1b1..031838c326775fe234cfd0cb7c6f18cbca7b0eaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ -src/__pycache__/* -__pycache__/* +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + output/* notes.html +.DS_Store \ No newline at end of file diff --git a/gen.py b/gen.py new file mode 100644 index 0000000000000000000000000000000000000000..7dcb4447c13cd1e13e4dbbf0b4ee63d0ec25e5fd --- /dev/null +++ b/gen.py @@ -0,0 +1,56 @@ +try: + import mistune +except ImportError as err: + print("Please install mistune to make use of markdown parsing.") + print("\t pip install mistune") + +import importlib +import argparse +import os +import sys + +# local import +import hallgrim.IliasXMLCreator.multi +import hallgrim.parser +from hallgrim.messages import * + +def filename_to_module(name): + return name.rstrip('.py').replace('/', '.') + +def parseme(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-o', + '--out', + help='Output file', + type=argparse.FileType('w'), + metavar='FILE') + parser.add_argument( + '-i', + '--input', + help='Script to execute', + metavar='FILE') + + args = parser.parse_args() + return args.out, args.input + + +def main(): + output, script_name = parseme() + script = importlib.import_module(filename_to_module(script_name)) + data = { + 'description': "_description", + 'question_text': mistune.markdown(script.task), + 'author': script.meta['author'], + 'title': script.meta['title'], + 'maxattempts': '0', + 'shuffle': True, + 'questions': hallgrim.parser.choice_parser(script.choices), + } + + output = os.path.join('output', script.meta['title']) + '.xml' if not output else output + hallgrim.IliasXMLCreator.multi.convert_and_print(data, output) + info('Processed "{}" and wrote xml to "{}".'.format(script_name, output)) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/hallgrim/IliasXMLCreator/__init__.py b/hallgrim/IliasXMLCreator/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/hallgrim/IliasXMLCreator/multi.py b/hallgrim/IliasXMLCreator/multi.py new file mode 100644 index 0000000000000000000000000000000000000000..dece6b7887e32ceded6415a7cfa20e221759291e --- /dev/null +++ b/hallgrim/IliasXMLCreator/multi.py @@ -0,0 +1,151 @@ +import xml.etree.ElementTree as et + + +def simple_elemet(name, text=None, attrib={}): + if not text: + return et.Element(name, attrib=attrib) + node = et.Element(name, attrib=attrib) + node.text = text + return node + + +def qtimetadatafield(label, entry): + root = et.Element('qtimetadatafield') + root.append(simple_elemet('fieldlabel', text=label)) + root.append(simple_elemet('fieldentry', text=entry)) + return root + + +def itemmetadata(type, author, feedback_setting=1): + subroot = et.Element('qtimetadata') + subroot.append(qtimetadatafield('ILIAS_VERSION', '5.1.8 2016-08-03')) + subroot.append(qtimetadatafield('QUESTIONTYPE', type)) + subroot.append(qtimetadatafield('AUTHOR', author)) + subroot.append(qtimetadatafield('additional_cont_edit_mode', 'default')) + subroot.append(qtimetadatafield('externalId', '99.99')) + subroot.append(qtimetadatafield('thumb_size', None)) + subroot.append(qtimetadatafield('feedback_setting', str(feedback_setting))) + root = et.Element('itemmetadata') + root.append(subroot) + return root + +########################################################################## + + +def material(content): + material = et.Element('material') + material.append(simple_elemet( + 'mattext', + text=content, + attrib={'texttype': 'text/xhtml'} + )) + return material + + +def response_label(content, count): + response_label = et.Element('response_label', attrib={'ident': str(count)}) + response_label.append(material(content)) + return response_label + + +def presentation(title, question_text, questions, shuffle=True): + root = et.Element('presentation', attrib={'label': title}) + flow = et.Element('flow') + response_lid = et.Element( + 'response_lid', attrib={'ident': 'MCMR', 'rcardinality': 'Multiple'}) + render_choice = et.Element( + 'render_choice', attrib={'shuffle': 'Yes' if shuffle else 'No'}) + for i, (answer, _, _) in enumerate(questions): + render_choice.append(response_label(answer, i)) + + root.append(flow) + flow.append(material(question_text)) + flow.append(response_lid) + response_lid.append(render_choice) + return root + +########################################################################## + + +def respcondition(points, count, correct=True): + root = et.Element('respcondition', attrib={'continue': 'Yes'}) + conditionvar = et.Element('conditionvar') + varequal = simple_elemet( + 'varequal', + text=str(count), + attrib={'respident': 'MCMR'} + ) + + if correct: + conditionvar.append(varequal) + else: + _not = et.Element('not') + _not.append(varequal) + conditionvar.append(_not) + + root.append(conditionvar) + + setvar = simple_elemet( + 'setvar', + text=str(points), + attrib={'action': 'Add'} + ) + root.append(setvar) + + if correct: + displayfeedback = et.Element( + 'displayfeedback', + attrib={'feedbacktype': 'Response', + 'linkrefid': 'response_{}'.format(count)}) + root.append(displayfeedback) + return root + + +def resprocessing(questions): + root = et.Element('resprocessing') + outcomes = et.Element('outcomes') + outcomes.append(simple_elemet('decvar')) + root.append(outcomes) + for i, (_, correct, points) in enumerate(questions): + root.append(respcondition(points if correct else 0, i, True)) + root.append(respcondition(points if not correct else 0, i, False)) + return root + + +########################################################################## +def itemfeedback(count): + root = et.Element( + 'itemfeedback', + attrib={'ident': 'response_{}'.format(count), 'view': 'All'} + ) + flow_mat = et.Element('flow_mat') + flow_mat.append(material('NONE')) + root.append(flow_mat) + return root +########################################################################## + + +def create_xml_tree(description, question_text, author, title, maxattempts, shuffle, questions): + root = et.Element('questestinterop') + tree = et.ElementTree(root) + item = et.Element('item', attrib={ + 'ident': 'undefined', + 'title': title, + 'maxattempts': maxattempts + }) + + item.append(simple_elemet('description', text=description)) + item.append(simple_elemet('duration', text='P0Y0M0DT0H30M0S')) + item.append(itemmetadata('MULTIPLE CHOICE QUESTION', author)) + item.append(presentation(title, question_text, questions, shuffle)) + item.append(resprocessing(questions)) + for i, _ in enumerate(questions): + item.append(itemfeedback(i)) + root.append(item) + + return tree + + +def convert_and_print(data, output): + tree = create_xml_tree(**data) + tree.write(output, encoding="utf-8", xml_declaration=True) diff --git a/hallgrim/IliasXMLCreator/single.py b/hallgrim/IliasXMLCreator/single.py new file mode 100644 index 0000000000000000000000000000000000000000..7e4c217c3b12eedf5c004489515625139aa51b62 --- /dev/null +++ b/hallgrim/IliasXMLCreator/single.py @@ -0,0 +1,4 @@ +import xml.etree.ElementTree as ET + +tree = ET.parse('country_data.xml') +root = tree.getroot() \ No newline at end of file diff --git a/hallgrim/__init__.py b/hallgrim/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/hallgrim/ilias_templates/multiple choice/1478003900__9310__qpl_82996.xml b/hallgrim/ilias_templates/multiple choice/1478003900__9310__qpl_82996.xml new file mode 100755 index 0000000000000000000000000000000000000000..013cf67bb6e30ce8f60717b69a88a4dd13e9b41e --- /dev/null +++ b/hallgrim/ilias_templates/multiple choice/1478003900__9310__qpl_82996.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE Test + SYSTEM 'http://www.ilias.uni-koeln.de/download/dtd/ilias_co.dtd'> +<!--Export of ILIAS Test Questionpool 82996 of installation .--> +<ContentObject Type="Questionpool_Test"> + <MetaData> + <General Structure="Hierarchical"> + <Identifier Catalog="ILIAS" Entry="il_9310_qpl_82996"/> + <Title Language="de">Aufgabentypen aus ILIAS</Title> + <Language Language="de"/> + <Description Language="de">Eine Sammlung von Prototypen, um sie automatisch generieren zu können.</Description> + <Keyword Language="de"/> + </General> + </MetaData> + <Settings> + <ShowTaxonomies>0</ShowTaxonomies> + <NavTaxonomy>0</NavTaxonomy> + <SkillService>0</SkillService> + </Settings> + <PageObject> + <PageContent> + <Question QRef="il_9310_qst_1662595"/> + </PageContent> + </PageObject> +</ContentObject> \ No newline at end of file diff --git a/hallgrim/ilias_templates/multiple choice/1478003900__9310__qti_82996.xml b/hallgrim/ilias_templates/multiple choice/1478003900__9310__qti_82996.xml new file mode 100644 index 0000000000000000000000000000000000000000..5532a77849bcecc8df6826b1e335f641ce9e3e36 --- /dev/null +++ b/hallgrim/ilias_templates/multiple choice/1478003900__9310__qti_82996.xml @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE questestinterop + SYSTEM 'ims_qtiasiv1p2p1.dtd'> +<!--Generated by ILIAS XmlWriter--> +<questestinterop> + <item ident="il_9310_qst_1662595" maxattempts="0" title="template Multiple Choice"> + <qticomment>Description</qticomment> + <duration>P0Y0M0DT0H4M0S</duration> + <itemmetadata> + <qtimetadata> + <qtimetadatafield> + <fieldlabel>ILIAS_VERSION</fieldlabel> + <fieldentry>5.1.8 2016-08-03</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>QUESTIONTYPE</fieldlabel> + <fieldentry>MULTIPLE CHOICE QUESTION</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>AUTHOR</fieldlabel> + <fieldentry>Jan Maximilian Michal</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>additional_cont_edit_mode</fieldlabel> + <fieldentry>default</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>externalId</fieldlabel> + <fieldentry>58188690c7a837.82372605</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>thumb_size</fieldlabel> + <fieldentry/> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>feedback_setting</fieldlabel> + <fieldentry>1</fieldentry> + </qtimetadatafield> + </qtimetadata> + </itemmetadata> + <presentation label="template Multiple Choice"> + <flow> + <material> + <mattext texttype="text/xhtml"><p>Question Text</p></mattext> + </material> + <response_lid ident="MCMR" rcardinality="Multiple"> + <render_choice shuffle="Yes"> + <response_label ident="0"> + <material> + <mattext texttype="text/xhtml"><p>Answer A</p></mattext> + </material> + </response_label> + <response_label ident="1"> + <material> + <mattext texttype="text/xhtml"><p>Answer B</p></mattext> + </material> + </response_label> + <response_label ident="2"> + <material> + <mattext texttype="text/xhtml"><p>Answer C</p></mattext> + </material> + </response_label> + </render_choice> + </response_lid> + </flow> + </presentation> + <resprocessing> + <outcomes> + <decvar/> + </outcomes> + <respcondition continue="Yes"> + <conditionvar> + <varequal respident="MCMR">0</varequal> + </conditionvar> + <setvar action="Add">2</setvar> + <displayfeedback feedbacktype="Response" linkrefid="response_0"/> + </respcondition> + <respcondition continue="Yes"> + <conditionvar> + <not> + <varequal respident="MCMR">0</varequal> + </not> + </conditionvar> + <setvar action="Add">1</setvar> + </respcondition> + <respcondition continue="Yes"> + <conditionvar> + <varequal respident="MCMR">1</varequal> + </conditionvar> + <setvar action="Add">3.5</setvar> + <displayfeedback feedbacktype="Response" linkrefid="response_1"/> + </respcondition> + <respcondition continue="Yes"> + <conditionvar> + <not> + <varequal respident="MCMR">1</varequal> + </not> + </conditionvar> + <setvar action="Add">0</setvar> + </respcondition> + <respcondition continue="Yes"> + <conditionvar> + <varequal respident="MCMR">2</varequal> + </conditionvar> + <setvar action="Add">0</setvar> + <displayfeedback feedbacktype="Response" linkrefid="response_2"/> + </respcondition> + <respcondition continue="Yes"> + <conditionvar> + <not> + <varequal respident="MCMR">2</varequal> + </not> + </conditionvar> + <setvar action="Add">1</setvar> + </respcondition> + </resprocessing> + <itemfeedback ident="response_0" view="All"> + <flow_mat> + <material> + <mattext texttype="text/plain"/> + </material> + </flow_mat> + </itemfeedback> + <itemfeedback ident="response_1" view="All"> + <flow_mat> + <material> + <mattext texttype="text/plain"/> + </material> + </flow_mat> + </itemfeedback> + <itemfeedback ident="response_2" view="All"> + <flow_mat> + <material> + <mattext texttype="text/plain"/> + </material> + </flow_mat> + </itemfeedback> + </item> +</questestinterop> \ No newline at end of file diff --git a/hallgrim/ilias_templates/single choice/1478020233__9310__qpl_82996.xml b/hallgrim/ilias_templates/single choice/1478020233__9310__qpl_82996.xml new file mode 100755 index 0000000000000000000000000000000000000000..8abe3eb94fb25432fffecc2d26f367e43b8e0cfc --- /dev/null +++ b/hallgrim/ilias_templates/single choice/1478020233__9310__qpl_82996.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE Test + SYSTEM 'http://www.ilias.uni-koeln.de/download/dtd/ilias_co.dtd'> +<!--Export of ILIAS Test Questionpool 82996 of installation .--> +<ContentObject Type="Questionpool_Test"> + <MetaData> + <General Structure="Hierarchical"> + <Identifier Catalog="ILIAS" Entry="il_9310_qpl_82996"/> + <Title Language="de">Aufgabentypen aus ILIAS</Title> + <Language Language="de"/> + <Description Language="de">Eine Sammlung von Prototypen, um Aufgabe automatisch generieren zu können.</Description> + <Keyword Language="de"/> + </General> + </MetaData> + <Settings> + <ShowTaxonomies>0</ShowTaxonomies> + <NavTaxonomy>0</NavTaxonomy> + <SkillService>0</SkillService> + </Settings> + <PageObject> + <PageContent> + <Question QRef="il_9310_qst_1662594"/> + </PageContent> + </PageObject> +</ContentObject> \ No newline at end of file diff --git a/hallgrim/ilias_templates/single choice/1478020233__9310__qti_82996.xml b/hallgrim/ilias_templates/single choice/1478020233__9310__qti_82996.xml new file mode 100644 index 0000000000000000000000000000000000000000..2c4465ff67b893b1f873759ab5b8fbdfc9fb06b1 --- /dev/null +++ b/hallgrim/ilias_templates/single choice/1478020233__9310__qti_82996.xml @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE questestinterop + SYSTEM 'ims_qtiasiv1p2p1.dtd'> +<!--Generated by ILIAS XmlWriter--> +<questestinterop> + <item ident="il_9310_qst_1662594" maxattempts="0" title="template Single Choice"> + <qticomment>Description</qticomment> + <duration>P0Y0M0DT0H4M0S</duration> + <itemmetadata> + <qtimetadata> + <qtimetadatafield> + <fieldlabel>ILIAS_VERSION</fieldlabel> + <fieldentry>5.1.8 2016-08-03</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>QUESTIONTYPE</fieldlabel> + <fieldentry>SINGLE CHOICE QUESTION</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>AUTHOR</fieldlabel> + <fieldentry>Jan Maximilian Michal</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>additional_cont_edit_mode</fieldlabel> + <fieldentry>default</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>externalId</fieldlabel> + <fieldentry>58188608584f51.87879156</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>thumb_size</fieldlabel> + <fieldentry/> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>feedback_setting</fieldlabel> + <fieldentry>2</fieldentry> + </qtimetadatafield> + </qtimetadata> + </itemmetadata> + <presentation label="template Single Choice"> + <flow> + <material> + <mattext texttype="text/xhtml"><p>Question Text</p></mattext> + </material> + <response_lid ident="MCSR" rcardinality="Single"> + <render_choice shuffle="Yes"> + <response_label ident="0"> + <material> + <mattext texttype="text/xhtml"><p>Antwort A</p></mattext> + </material> + </response_label> + <response_label ident="1"> + <material> + <mattext texttype="text/xhtml"><p>Antwort B</p></mattext> + </material> + </response_label> + <response_label ident="2"> + <material> + <mattext texttype="text/xhtml"><p>Antwort C</p></mattext> + </material> + </response_label> + </render_choice> + </response_lid> + </flow> + </presentation> + + <resprocessing> + <outcomes> + <decvar/> + </outcomes> + <respcondition continue="Yes"> + <conditionvar> + <varequal respident="MCSR">0</varequal> + </conditionvar> + <setvar action="Add">0</setvar> + <displayfeedback feedbacktype="Response" linkrefid="response_0"/> + </respcondition> + + <respcondition continue="Yes"> + <conditionvar> + <varequal respident="MCSR">1</varequal> + </conditionvar> + <setvar action="Add">314</setvar> + <displayfeedback feedbacktype="Response" linkrefid="response_1"/> + </respcondition> + + <respcondition continue="Yes"> + <conditionvar> + <varequal respident="MCSR">2</varequal> + </conditionvar> + <setvar action="Add">0</setvar> + <displayfeedback feedbacktype="Response" linkrefid="response_2"/> + </respcondition> + + </resprocessing> + <itemfeedback ident="response_0" view="All"> + <flow_mat> + <material> + <mattext texttype="text/plain"/> + </material> + </flow_mat> + </itemfeedback> + <itemfeedback ident="response_1" view="All"> + <flow_mat> + <material> + <mattext texttype="text/plain"/> + </material> + </flow_mat> + </itemfeedback> + <itemfeedback ident="response_2" view="All"> + <flow_mat> + <material> + <mattext texttype="text/plain"/> + </material> + </flow_mat> + </itemfeedback> + </item> +</questestinterop> \ No newline at end of file diff --git a/hallgrim/messages.py b/hallgrim/messages.py new file mode 100644 index 0000000000000000000000000000000000000000..9f66c17a739612b9d81dc4555b47f1025bc8c488 --- /dev/null +++ b/hallgrim/messages.py @@ -0,0 +1,8 @@ +def warn(msg): + print('[WARN]', msg) + +def debug(msg): + print('[DEBUG]', msg) + +def info(msg): + print('[INFO]', msg) \ No newline at end of file diff --git a/hallgrim/parser.py b/hallgrim/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..c344b32c504b91c2c4d4c4a6bb56161163e7b233 --- /dev/null +++ b/hallgrim/parser.py @@ -0,0 +1,8 @@ +import re +import mistune + +def choice_parser(raw_choices): + lines = raw_choices.strip().split('\n') + parse = [re.match('\[(X| )\] (.*)', line).groups() for line in lines] + final = [(mistune.markdown(text), True if mark == 'X' else False, 0.5) for mark, text in parse] + return final diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/scripts/multi_proto.py b/scripts/multi_proto.py new file mode 100644 index 0000000000000000000000000000000000000000..3c470a7fe1ef0d6a204b7f278d7585f9f658cf09 --- /dev/null +++ b/scripts/multi_proto.py @@ -0,0 +1,38 @@ +meta = { + 'author': 'Jan Maximilian Michal', + 'title': 'Sortieren nach Punkten (I1-ID: nipe84411eh0)', + 'type': 'multiple choice', +} + +task = """ Hier der Anfang der Datei `punkte.csv`, die Komma-getrennte Angaben +zu erreichten Übungspunkten enthält: + +``` +21600001,Herr,Bollman,Fritze-Peter,15 +21600002,Frau,Bollwoman,Franzi,19 +21600003,Herr,Lindemann,Erwin,17 +21600004,Frau,Lindefrau,Edelgard Martha,12 +21600005,Herr,Machtnix,Mike,2 +..... +``` + +Welches Shell-Kommando ist geeignet, die Zeilen nach fallender Punktzahl +sortiert auszugeben (also erst große, dann kleinere Punktzahlen)? """ + +choices = """ +[ ] `sort --reverse --k 5 --numeric-sort punkte.csv` +[X] `sort --r --field-separator=, -k 5 --n punkte.csv` +[ ] `sort -r -t="," -k 5 --n punkte.csv` +[X] `sort --reverse -t "," -k 5 -n punkte.csv` +[ ] `sort -r --field-separator "," -k 4 -numeric punkte.csv` +[ ] `sort -r --field-separator "," -k 4 punkte.csv` +""" + +explanations = """ +[ ] sort --reverse --k 5 --numeric-sort punkte.csv falsch (u.a.: ungültiges Argument --k) +[ ] sort --r --field-separator=, -k 5 --n punkte.csv falsch (u.a.: bei kurzem Argument -k darf kein = stehen) +[ ] sort -r -t="," -k 5 --n punkte.csv falsch (siehe oben) +[X] sort --reverse -t "," -k 5 -n punkte.csv richtig +[ ] sort -r --field-separator "," -k 4 -numeric punkte.csv falsch (u.a.: Punkte stehen in Spalte 5) +[ ] sort -r --field-separator "," -k 4 punkte.csv falsch (u.a.: keine numerische Sortierung) +""" \ No newline at end of file