Welcome to HBH! If you had an account on hellboundhacker.org you will need to reset your password using the Lost Password system before you will be able to login.

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