Welcome to HBH! If you have tried to register and didn't get a verification email, please using the following link to resend the verification email.

Test Conversion Program / Blackboard LMS QTI to Respondus Format - Python Code Bank


Test Conversion Program / Blackboard LMS QTI to Respondus Format
Today I had to write a program to convert a broken Blackboard QTI content packet to Respondus format (A software product my work uses to upload tests to our Angel LMS). Thought I provide another real world application the data file can be downloaded here: [url]http://pastebin.com/QeP8L1Aa[/url] Just save it as: res00001.dat
                import re

#==================================================================#
# This file was created to fix a broken Blackboard Content Package #
#==================================================================#
'''
    Note: qti_assessment is used as a global list,
        the structure of this list is as follows:

            qti_assessment = [ [
                                "Type: <QTYPE>", #question type: if needed by Repondus: Matching
                                "<TITLE>",       #title of the question
                                {'id_hash':'<choice>'}, #dictionary to store response data: t/f questions: {'true':'True', 'false':'False'}
                                "<Answer>" #answer to the question, also used to check for response to place a * in front
                               ],
                               [...],
                               [...]
                             ]
'''
def Matching(qti_question):
    """This function reformats the matching questions to a readable data structure"""
    global qti_assessment
    #get the title of the question
    _TITLE_ = getTitle(qti_question)
    lst_title = _TITLE_.split('<br>')
    #print(lst_title)
    _choices_fix = {}
    _roman_match = []
    counter = 0
    for i in range(1,len(lst_title),1):
        first_dot = lst_title[i].find('. ')+2
        second_dot = lst_title[i].find('. ', 5)+2
        _roman_match += [lst_title[i][first_dot:second_dot-4]]
        #get the choice and update the dictionary: _choices_fix
        _choices_fix.update({chr(65+counter):lst_title[i][second_dot:]})
        counter+=1
   
    #create a temp dictionary to reformat data
    _CHOICES_ = {}
    _ANS_ = getAns(qti_question).split(', ')

    for i in range(0,len(_ANS_)):
        _CHOICES_.update({str(i):_roman_match[i]+' = '+_choices_fix[_ANS_[i]]})
        
    qti_assessment += [["Type: MT\n",_TITLE_, _CHOICES_, "N/A"]] #qti_assessment = [[str(title), {id:choice}, str(id)],...]


def FillInTheBlank():
    """This function reformats the fill in the blank questions to a readable data structure"""

def TrueFalse(qti_question):
    """This function reformats the true/false questions to a readable data structure"""
    global qti_assessment
    #get the title of the question
    _TITLE_ = getTitle(qti_question)
    _ANS_ = getAns(qti_question)
    qti_assessment += [["",_TITLE_, {'true':'True','false':'False'}, _ANS_]] #qti_assessment = [[str(title), {id:choice}, str(id)],...]

def MultipleChoice(qti_question):
    """This function reformats the multiple choice questions to a readable data structure"""
    global qti_assessment
    #get the title of the question
    _TITLE_ = getTitle(qti_question)

    _RESPONSES_ = qti_responses.findall(qti_question) #get a list of the choices
    choices = {} #create a temp dictionary to store data restructured data
    for response in _RESPONSES_: #for each reponse available
        _choice_fix = ""
        _ID_ = qti_label_indent.findall(response)[0] #get the hash id for checking
        _CHOICE_ = qti_choice.findall(response) #get the choice text
        for c in _CHOICE_:
            if c != '':
                _choice_fix += c
        choices.update({_ID_:_choice_fix}) #make a dictionary to store id:text
    _ANS_ = getAns(qti_question)
    qti_assessment += [["",_TITLE_, choices, _ANS_]] #qti_assessment = [[str(title), {id:choice}, str(id)],...]

def getTitle(qti_question):
    return qti_title.findall(qti_question)[0].replace('&lt;br/&gt;','<br>').replace('&amp;#58;', ': ').replace('    ','').replace('&amp;quot;','"').replace('&#160;','')

def getAns(qti_question):
    return qti_answer.findall(qti_question)[0] #get the correct answer for comparing

def ProcessQType(qtype, qti_question):
    """This function delagates the qtype and returns a readable data structure"""
    if qtype == 'Multiple Choice': result = MultipleChoice(qti_question)
    if qtype == 'True/False': result = TrueFalse(qti_question)
    if qtype == 'Fill in the Blank': result = Matching(qti_question)


#------------------------------------------------------------------#
#open .dat file and store qti questions lists
fname = 'res00001.dat'
path = './'
f = open(path+fname,'r')
data = f.read()
f.close()

#Strip data of all escape characters
data = data.replace('\t','').replace('\n','')

#Create a questions list to store qti question data chunks
regex = re.compile(r'<item.*?>(.*?)</item>')
qti_questions = regex.findall(data)

#loop through each question and extract relavent data:
#Title, Choices, Correct Answer
#And write it out in Respondus format for Import/Export to Angel
#----------------------------------------
#Some regular expressions to store patterns
#and setup question order for Repondus
#----------------------------------------
#get the assessment title
qti_assessment_title = re.compile(r'<assessment title="(.*?)">', re.DOTALL)
#reasign fname to new filename
fname = qti_assessment_title.findall(data)[0]

#get the title for the question
qti_title = re.compile(r'<flow class="FORMATTED_TEXT_BLOCK"><material><mat_extension><mat_formattedtext type="HTML">(.*?)</mat_formattedtext></mat_extension></material></flow>', re.DOTALL)

#get the question type: for processing
qti_qtype = re.compile(r'<bbmd_questiontype>(.*?)</bbmd_questiontype>')

#get each response to search through
qti_responses = re.compile(r'<flow_label class="Block">(.*?)</flow_label>')

#get label id and check for correct answer
qti_label_indent = re.compile(r'<response_label ident="(.*?)"')

#get response text
qti_choice = re.compile(r'<mat_formattedtext type="HTML">(.*?)</mat_formattedtext>')


#get the correct answer id to compare reponses with
qti_answer = re.compile(r'<varequal case="No" respident="response">(.*?)</varequal>')

#final output list to write out to file containing all relavent data
qti_assessment = []
for i in range(0,len(qti_questions),1):
    qti_question = qti_questions[i] #each question in qti_questions

    #get the qtype of the question
    _QTYPE_ = qti_qtype.findall(qti_question)[0]
    ProcessQType(_QTYPE_,qti_question)
    
    #finally loop through assessment and output a Respondus formatted .txt file
f = open(path+fname+'.txt', 'w')
for i in range(0, len(qti_assessment),1):
    qnum = str(i+1)+'. ';
    #begin question
    qti_question = qti_assessment[i][1]
    qti_qtype = qti_assessment[i][0]
    #if match process()
    f.write(qti_qtype+qnum + qti_question+'\n')
    #---------------------------------------
    ans_id = qti_assessment[i][3]
    #print(ans_id)
    counter = 0
    for key, value in qti_assessment[i][2].items():
        if key == ans_id:
            f.write('*')
        f.write(chr(97+counter)+'. ' + value + '\n')
        counter+=1
    #---------------------------------------
    f.write('\n\n')
    #end question
f.close()



            
Comments
Sorry but there are no comments to display