1+ < html >
2+ < header >
3+ < title > Text questions to Moodle XML format</ title >
4+ </ header >
5+ < body >
6+ < script >
7+
8+ // Global variables
9+ var QuestionNumber = 1 ;
10+ var AllMultichoiceBool = true ;
11+ var NumberingChoice = "123" ;
12+ var ShuffledAnswersBool = true ;
13+
14+ function CDataExtra ( Text )
15+ {
16+ return ( '<![CDATA[' + Text + ']]>' ) ;
17+ }
18+
19+ function GenerateXMLQuestion ( Question , Answers )
20+ {
21+ if ( Question === '' && Answers . length == 0 )
22+ {
23+ // nothing to do
24+ return ;
25+ }
26+
27+ // Working variables
28+ NumberOfAnswers = Answers . length ;
29+ NumberOfGoodAnswers = 0 ;
30+
31+ // Question with 1 or no answer
32+ if ( Question !== '' && NumberOfAnswers <= 1 )
33+ {
34+ alertstr = "Question with only 1 answer or without answer!!!!!!\n\nQuestion was:\n" + Question + "\n" ;
35+ for ( var i = 0 ; i < NumberOfAnswers ; i ++ )
36+ {
37+ alertstr += Answers [ i ] + "\n" ;
38+ }
39+ alert ( alertstr ) ;
40+ throw ( alertstr ) ;
41+ }
42+
43+ // Count number of good answers
44+ for ( var i = 0 ; i < NumberOfAnswers ; i ++ )
45+ {
46+ if ( Answers [ i ] [ 0 ] == '+' )
47+ {
48+ NumberOfGoodAnswers ++ ;
49+ continue ;
50+ }
51+ }
52+
53+ // No good answers?
54+ if ( NumberOfGoodAnswers == 0 )
55+ {
56+ alertstr = "Question without a good answer!!!!!!\n\n" + Question + "\n" ;
57+ for ( var i = 0 ; i < NumberOfAnswers ; i ++ )
58+ {
59+ alertstr += Answers [ i ] + "\n" ;
60+ }
61+ alert ( alertstr ) ;
62+ throw ( alertstr ) ;
63+ }
64+
65+ // Ok, at least 1 good answer and 2 answers in total, generate the question
66+ XMLQuestion = '<question type="multichoice">\n' ;
67+ XMLQuestion += '\t<name><text>' + CDataExtra ( Question ) + '</text></name>\n' ; QuestionNumber ++ ;
68+ XMLQuestion += '\t<generalfeedback format="html"><text></text></generalfeedback>\n' ;
69+ XMLQuestion += '\t<correctfeedback format="html"><text></text></correctfeedback>\n\t<partiallycorrectfeedback format="html"><text></text></partiallycorrectfeedback>\n\t<incorrectfeedback format="html"><text></text></incorrectfeedback>\n' ;
70+
71+ XMLQuestion += '\t<questiontext format="html">\n\t\t<text>' + CDataExtra ( Question ) + '</text>\n\t</questiontext>\n' ;
72+ XMLQuestion += '\t<defaultgrade>1.0000000</defaultgrade>\n' ;
73+ XMLQuestion += '\t<penalty>0.333333333</penalty>\n' ;
74+ XMLQuestion += '\t<answernumbering>' + NumberingChoice + '</answernumbering>\n' ;
75+
76+ XMLQuestion += '\t<hidden>0</hidden>\n' ;
77+ if ( AllMultichoiceBool === true || NumberOfGoodAnswers > 1 )
78+ {
79+ XMLQuestion += '\t<single>false</single>\n' ;
80+ }
81+ else
82+ {
83+ XMLQuestion += '\t<single>true</single>\n' ;
84+ }
85+ XMLQuestion += '\t<shuffleanswers>' + ShuffledAnswersBool . toString ( ) + '</shuffleanswers>\n' ;
86+
87+ // Fraction
88+ Fraction = ( 100 / NumberOfGoodAnswers ) . toString ( ) ;
89+
90+ // Generate questions
91+ for ( var i = 0 ; i < NumberOfAnswers ; i ++ )
92+ {
93+ // Good answer
94+ if ( Answers [ i ] [ 0 ] == '+' )
95+ {
96+ XMLQuestion += '\t<answer fraction="' + Fraction + '"' ;
97+ }
98+ else
99+ {
100+ XMLQuestion += '\t<answer fraction="0" ' ;
101+ }
102+
103+ XMLQuestion += ' format="html">\n\t\t<text>' + CDataExtra ( Answers [ i ] . replace ( / ^ [ + - ] \s * / , '' ) ) + '</text>\n\t\t<feedback format="html"><text></text></feedback>\n\t</answer>\n' ;
104+ }
105+
106+ XMLQuestion += '</question>\n' ;
107+
108+ return XMLQuestion ;
109+ }
110+
111+ function CreateXMLFile ( )
112+ {
113+ // Get values from the form
114+ filename = document . getElementById ( 'filename' ) . value ;
115+ questionlist = document . getElementById ( 'questionlist' ) . value ;
116+
117+ if ( questionlist . replace ( / ^ \s + | \s + $ / g, '' ) . replace ( / \s + / g, ' ' ) === '' )
118+ {
119+ alert ( "No questions given!!!" ) ;
120+ return ;
121+ }
122+
123+ // Working variables
124+ CurrentQuestion = '' ;
125+ CurrentAnswers = [ ] ;
126+
127+ // Reset global question number to 1
128+ QuestionNumber = 1 ;
129+ AllMultichoiceBool = document . getElementById ( "multichoice" ) . checked ;
130+ NumberingChoice = document . getElementById ( "Numbering" ) . value ;
131+ ShuffledAnswersBool = document . getElementById ( "shuffled" ) . value ;
132+
133+ // Start document with XML Prolog
134+ QuestionList = '<?xml version="1.0" encoding="UTF-8"?>\n<quiz>\n\n' ;
135+
136+ // Is there a category?
137+ Category = document . getElementById ( "category" ) . value ;
138+ if ( Category != '' )
139+ {
140+ QuestionList += '<!-- question: 0 -->\n<question type="category">\n\t<category><text>$course$/top</text></category>\n</question>\n' ;
141+ QuestionList += '<!-- question: 0 -->\n<question type="category">\n\t<category><text>$course$/top/' + CDataExtra ( Category ) + '</text></category>\n</question>\n\n' ;
142+ }
143+
144+ // parse text to make list of questions
145+ var lines = questionlist . split ( '\n' ) ;
146+ for ( var i = 0 ; i < lines . length ; i ++ )
147+ {
148+ // Current line without extra spaces
149+ CurrentLine = lines [ i ] . replace ( / ^ \s + | \s + $ / g, '' ) . replace ( / \s + / g, ' ' ) ;
150+
151+ // If current line is empty, go to next lines
152+ if ( CurrentLine === '' )
153+ {
154+ continue ;
155+ }
156+
157+ // console.log( CurrentLine );
158+
159+ // Is it an answer line ?
160+ if ( CurrentLine [ 0 ] === '+' || CurrentLine [ 0 ] === '-' )
161+ {
162+ if ( CurrentLine . replace ( / ^ [ + - ] \s * / , '' ) . replace ( / \s + / , '' ) === '' )
163+ {
164+ alert ( "Answer (line starting with + or -) but no answer label:\nQuestion was:\n" + CurrentQuestion + "\n\nCurrent line:\n" + lines [ i ] ) ;
165+ return ;
166+ }
167+
168+ // If CurrentQuestion is empty, answer before the question
169+ if ( CurrentQuestion === '' )
170+ {
171+ alert ( "Answer (line starting with + or -) before question label\n\nCurrent line:\n" + lines [ i ] ) ;
172+ return ;
173+ }
174+ CurrentAnswers . push ( CurrentLine ) ;
175+ }
176+ else
177+ {
178+ // We consider it is a question
179+ if ( CurrentQuestion !== '' )
180+ {
181+ // Ok, we have a previous question
182+
183+ // Check if previous question have answers
184+ if ( CurrentAnswers . length <= 1 )
185+ {
186+ // Ok, we have a question but no answer from the previous one
187+ alert ( "Question with only 1 answer or without answer!!!!!!\n\nQuestion was:\n" + CurrentQuestion + "\n\nCurrent line:\n" + lines [ i ] ) ;
188+ return ;
189+ }
190+
191+ // Generate question (with its answer) before setting the new one
192+ QuestionList += GenerateXMLQuestion ( CurrentQuestion , CurrentAnswers ) ;
193+ // CurrentQuestion = ''; => Useless here, we will set it just below to its new value
194+ CurrentAnswers = [ ] ;
195+ }
196+
197+ CurrentQuestion = CurrentLine ;
198+ continue ;
199+ }
200+ }
201+
202+ // Call with last (or no) question if text area is empty
203+ QuestionList += GenerateXMLQuestion ( CurrentQuestion , CurrentAnswers ) ;
204+ QuestionList += '\n\n</quiz>\n' ;
205+
206+ // download the generated xml into a file called filename
207+ // Code from https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server
208+ var element = document . createElement ( 'a' ) ;
209+ element . setAttribute ( 'href' , 'data:text/plain;charset=utf-8,' + encodeURIComponent ( QuestionList ) ) ;
210+ element . setAttribute ( 'download' , filename ) ;
211+
212+ element . style . display = 'none' ;
213+ document . body . appendChild ( element ) ;
214+
215+ element . click ( ) ;
216+
217+ document . body . removeChild ( element ) ;
218+ }
219+ </ script >
220+
221+ < p > Step 1: You need to copy/paste the list of question within the following text area. :</ p >
222+ < textarea id ="questionlist " style ="width: 80%;height:20em;display:block; "> </ textarea >
223+ < p > Step 2: Setup (or not) the category. If set, the category is a sub-bank of the question bank (category name can contain up to 20 letters, numbers, underscore and space):</ p >
224+ < input type ="text " id ="category " style ="display:block; " size ="50 " pattern ="[A-Za-z_0-9 ]{20} " value ="">
225+ < p > Step 3: Select if all questions are multichoice (thus, questions with 1 good answer will let student choose more than 1 answer):</ p >
226+ < input type ="checkbox " id ="multichoice " name ="multichoice " checked > < label for ="multichoice "> All questions are multichoice</ label >
227+ < p > Step 4: Select numbering of answers (default is none):</ p >
228+ < select id ="Numbering ">
229+ < option value ="123 "> 1, 2, 3, ...</ option >
230+ < option value ="abc "> a, b, c, ...</ option >
231+ < option value ="ABCD "> A, B, C, ...</ option >
232+ < option value ="iii "> i, ii, iii, ...</ option >
233+ < option value ="IIII "> I, II, III, ...</ option >
234+ < option value ="none " selected > No numbering</ option >
235+ </ select >
236+ < p > Step 5: Select if answer should be shuffled (default: yes):</ p >
237+ < input type ="checkbox " id ="shuffled " name ="shuffled " checked > < label for ="shuffled "> Shuffled answers</ label >
238+ < p > Step 6: Setup (or not) filename:</ p >
239+ < input type ="text " id ="filename " style ="display:block; " size ="50 " value ="QuestionInMoodleFormat.xml ">
240+ < p > Step 7: Click on the button to get your file. You will be able to import it Excel, LibreOffice, Google docs, ...</ p >
241+ < button onclick ="CreateXMLFile(); "> Create import File!</ button >
242+ </ body >
243+ </ html >
0 commit comments