####################
# source/testbank.py
####################
from xml.sax import parse as _parse
from xml.sax.handler import ContentHandler as _ContentHandler
################################################################################
class BankParser(_ContentHandler):
def __init__(self):
super().__init__()
self.context = []
def startElement(self, name, attrs):
if name == 'testbank':
# Validate
assert len(self.context) == 0
# Specific
name = attrs.getValue('name')
self.context.append(TestBank(name))
elif name == 'chapter':
# Validate
assert isinstance(self.context[-1], TestBank)
# Specific
name = attrs.getValue('name')
self.context.append(Chapter(name))
elif name == 'section':
# Validate
assert isinstance(self.context[-1], Chapter)
# Specific
name = attrs.getValue('name')
self.context.append(Section(name))
elif name == 'category':
# Validate
assert isinstance(self.context[-1], Section)
# Specific
kind = attrs.getValue('type')
assert kind in ('multiple_choice', 'true_or_false', 'matching')
self.context.append(Category(kind))
elif name == 'fact':
# Validate
assert isinstance(self.context[-1], Category)
# Specific
if self.context[-1].attr == 'multiple_choice':
kind = attrs.getValue('type')
self.context.append(Fact(kind))
else:
self.context.append(Fact())
elif name == 'question':
# Validate
assert isinstance(self.context[-1], Fact)
# Specific
self.context.append(Question())
elif name == 'answer':
# Validate
assert isinstance(self.context[-1], Fact)
# Specific
self.context.append(Answer())
else:
# Something is wrong with this document.
raise ValueError(name)
def characters(self, content):
self.context[-1].add_text(content)
def endElement(self, name):
node = self.context.pop()
if name == 'testbank':
self.TESTBANK = node
else:
self.context[-1].add_child(node)
################################################################################
class _Node:
def __init__(self, attr=None):
self.attr = attr
self.text = ''
self.children = []
def __repr__(self):
name = self.__class__.__name__.lower()
if self.attr is None:
attr = ''
else:
attr = ' {}="{}"'.format(self.ATTR_NAME, self.attr)
cache = '<{}{}>'.format(name, attr)
for child in self.children:
lines = repr(child).split('\n')
lines = map(lambda line: ' ' + line, lines)
cache += '\n' + '\n'.join(lines)
cache += self.text if self.ATTR_NAME is None else '\n'
cache += '</{}>'.format(name)
return cache
def add_text(self, content):
self.text += content
def add_child(self, node):
self.children.append(node)
################################################################################
class TestBank(_Node): ATTR_NAME = 'name'
class Chapter(_Node): ATTR_NAME = 'name'
class Section(_Node): ATTR_NAME = 'name'
class Category(_Node): ATTR_NAME = 'type'
class Fact(_Node): ATTR_NAME = 'type'
class Question(_Node): ATTR_NAME = None
class Answer(_Node): ATTR_NAME = None
################################################################################
def parse(filename):
parser = BankParser()
_parse(filename, parser)
return parser.TESTBANK