Sorry about your coffee cup! Would you be interested in a pyparsing rendition?
-- Paul from pyparsing import * def defineGrammar(): ParserElement.setDefaultWhitespaceChars(" \t") ident = Word(alphanums+"_") LT,GT = map(Suppress,"<>") NL = LineEnd().suppress() real = Word(nums,nums+".") integer = Word(nums) quotedString = QuotedString('"') dataValue = real | integer | Word(alphas,alphanums) | quotedString dataDef = ident + ZeroOrMore(dataValue) + NL tagDef = Forward() tagDef << LT + ident + ZeroOrMore(dataValue) + NL + \ Dict(ZeroOrMore(Group(dataDef) | Group(tagDef))) + GT + NL tagData = Dict(OneOrMore(Group(tagDef))) return tagData results = defineGrammar().parseString(TESTTXT) print( results.dump() ) print results.REAPER_PROJECT.TRACK.keys() print results.REAPER_PROJECT.TRACK.PANENV2 print results.REAPER_PROJECT.TRACK.PANENV2.ACT prints out: [['REAPER_PROJECT', '0.1', ['METRONOME', '6', '2.000000', ['SAMPLES', '', '']], ['TRACK', ['MAINSEND', '1'], ['VOLENV2', ['ACT', '1']], ['PANENV2', ['ACT', '1']]]]] - REAPER_PROJECT: ['0.1', ['METRONOME', '6', '2.000000', ['SAMPLES', '', '']], ['TRACK', ['MAINSEND', '1'], ['VOLENV2', ['ACT', '1']], ['PANENV2', ['ACT', '1']]]] - METRONOME: ['6', '2.000000', ['SAMPLES', '', '']] - SAMPLES: ['', ''] - TRACK: [['MAINSEND', '1'], ['VOLENV2', ['ACT', '1']], ['PANENV2', ['ACT', '1']]] - MAINSEND: 1 - PANENV2: [['ACT', '1']] - ACT: 1 - VOLENV2: [['ACT', '1']] - ACT: 1 ['PANENV2', 'MAINSEND', 'VOLENV2'] [['ACT', '1']] 1 -- http://mail.python.org/mailman/listinfo/python-list