diff --git a/otime/iof_xml.py b/otime/iof_xml.py new file mode 100644 index 0000000..95339d5 --- /dev/null +++ b/otime/iof_xml.py @@ -0,0 +1,182 @@ +import xml.etree.ElementTree as etree + +def xml_child(parent, tag, content): + # Used to make creating xml files easier + e = ET.SubElement(parent, tag) + e.text = str(content) + + def create_result_xml(self): + root = ET.Element('ResultList') + root.set('xmlns', 'http://www.orienteering.org/datastandard/3.0') + root.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance') + root.set('iofVersion', '3.0') + root.set('createTime', datetime.datetime.now().isoformat(timespec='seconds')) + root.set('creator', 'oTime') + root.set('status', 'Complete') + tree = ET.ElementTree(root) + event = ET.SubElement(root, 'Event') + xml_child(event, 'Id', self.id) + xml_child(event, 'Name', self.name) + for i in self.o_classes: + print('Hmmmmmm') + # + class_result = ET.SubElement(root, 'ClassResult') + # + t = ET.SubElement(class_result, 'Class') + xml_child(t, 'Name', i.name) + # + runners_same_c = get_runners_in_class(self.runners, i) + runners_ranked = rank_runners(runners_same_c, i) + # Put the OK runners first and Active last + runners_sorted = [i for i in runners_same_c if i not in runners_ranked] + runners_ranked.extend(runners_sorted) + + for n in runners_ranked: + person_result = ET.SubElement(class_result, 'PersonResult') + # + person = ET.SubElement(person_result, 'Person') + xml_child(person, 'Id', n.id) + # + name = ET.SubElement(person, 'Name') + xml_child(name, 'Family', n.last) + xml_child(name, 'Given', n.first) + # + # + # + org = ET.SubElement(person_result, 'Organisation') + xml_child(org, 'Id', n.club_id) + xml_child(org, 'Name', n.club) + country = ET.SubElement(org, 'Country') + # TODO: hent land fra løperobjektet + country.text = 'Norway' + country.set('code', 'NOR') + # + # + result = ET.SubElement(person_result, 'Result') + + # TODO: Dette bør skrives om til å bruke Runner metoder så mye som mulig. + if hasattr(n, 'card_r') and len(n.card_r.splits) > 2: + xml_child(result, 'StartTime', n.card_r.s_time.isoformat()) + xml_child(result, 'FinishTime', n.card_r.f_time.isoformat()) + xml_child(result, 'Time', n.totaltime()) + if n.status() == 'OK': + # + xml_child(result, 'TimeBehind', n.totaltime() - runners_ranked[0].totaltime()) + # + xml_child(result, 'Position', n.rank(self.runners)) + xml_child(result, 'Status', n.status()) + # + # TODO: ta utgangspunkt i løypa, ikke det brikka har stempla + for code, split in zip(n.card_r.controls, n.card_r.splits): + st = ET.SubElement(result, 'SplitTime') + xml_child(st, 'ControlCode', code) + xml_child(st, 'Time', split) + if code == n.res_codes()[-1]: + break + # + elif n.status() == 'Disqualified': + xml_child(result, 'Status', n.status()) + for code, split in zip(n.res_codes(), n.res_splits()): + st = ET.SubElement(result, 'SplitTime') + xml_child(st, 'ControlCode', code) + if split is not None: + xml_child(st, 'Time', split) + else: + xml_child(result, 'Status', n.status()) + else: + xml_child(result, 'Status', n.status()) + # + # + # + ET.indent(root, space=' ', level=0) + return tree + +def runners_from_xml_entries(xml_file): + tree = ET.parse(xml_file) + root = tree.getroot() + + url = '{http://www.orienteering.org/datastandard/3.0}' + runners = [] + person_entries = root.findall(f'./{url}PersonEntry') + for p_entry in person_entries: + + rid = p_entry[1][0].text + + person = p_entry.find(f'./{url}Person') + name = person.find(f'./{url}Name') + first = name.find(f'./{url}Given').text + last = name.find(f'./{url}Family').text + + organisation = p_entry.find(f'./{url}Organisation') + if organisation is not None: + club_id = organisation.find(f'./{url}Id').text + club_name = organisation.find(f'./{url}Name').text + club_name_short = organisation.find(f'./{url}ShortName').text + country = organisation.find(f'./{url}Country').attrib['code'] + else: + club_id = club_name = club_name_short = country = None + + class_el = p_entry.find(f'./{url}Class') + class_str = class_el.find(f'./{url}Name').text + + fee_id = int(p_entry.find(f'./{url}AssignedFee/{url}Fee/{url}Id').text) + + try: + card = int(p_entry.find(f'./{url}ControlCard').text) + except AttributeError: + card = None + + start_time = None + runners.append(Runner(rid, first, last, club=club_name, club_id=club_id, + country=country,card=card, o_class_str=class_str, + start_time=start_time, fee_id=fee_id)) + return runners + +def fees_from_xml_entries(xml_file): + tree = ET.parse(xml_file) + root = tree.getroot() + + url = '{http://www.orienteering.org/datastandard/3.0}' + allfees = root.findall(f'.//{url}Fee') + added_ids = [] + fee_objs = [] + for fee in allfees: + f_id = int(fee.find(f'./{url}Id').text) + if f_id not in added_ids: + added_ids.append(f_id) + + fee_id = f_id + name = fee.find(f'./{url}Name').text + currency = fee.find(f'./{url}Amount').attrib['currency'] + amount = int(fee.find(f'./{url}Amount').text) + try: + from_birth_date = fee.find(f'./{url}FromDateOfBirth').text + except AttributeError: + from_birth_date = None + try: + to_birth_date = fee.find(f'./{url}ToDateOfBirth').text + except AttributeError: + to_birth_date = None + + fee_objs.append(Fee(fee_id, name, currency, amount, + from_birth_date=from_birth_date, to_birth_date=to_birth_date)) + return fee_objs + +def courses_from_xml(xml_file): + tree = ET.parse(xml_file) + root = tree.getroot() + + url = '{http://www.orienteering.org/datastandard/3.0}' + allcourses = root.findall(f'.//{url}Course') + courseobjs = [] + for c in allcourses: + name = c.find(f'./{url}Name').text + controls = [] + allcontrols = c.findall(f'./{url}CourseControl') + for n in allcontrols: + controls.append(n.find(f'./{url}Control').text) + controls.remove('STA1') + controls.remove('FIN1') + controls = [int(l) for l in controls] + courseobjs.append(Course(name, controls)) + return courseobjs diff --git a/otime/otime.py b/otime/otime.py index 33a1e13..05796f2 100644 --- a/otime/otime.py +++ b/otime/otime.py @@ -20,6 +20,7 @@ class Runner: self.start_time = start_time self.fee_id = fee_id self.status_override = '' + def __repr__(self): return(f'name({self.fullname()})') @@ -62,71 +63,6 @@ class Runner: def fullname(self): return '{} {}'.format(self.first, self.last) - # TODO: må forbedres - def rank(self, allrunners): - c_ranked = rank_runners(allrunners, self.o_class) - try: - return c_ranked.index(self) + 1 - except ValueError: - return None - - def get_codes(self): - if self.o_class.course.forked is False: - return self.o_class.course.codes - else: - return self.o_class.course.variations[self.fork] - - # TODO: Mange bugs med løyper som har samme post flere ganger - # Used for making result files and tables - def get_splits(self): - if self.status() == 'OK': - splits_cpy = self.card_r.splits.copy() - for control in self.card_r.controls: - if control not in self.res_codes(): - index = self.card_r.controls.index(control) - split = self.card_r.splits[index] - splits_cpy.remove(split) - return splits_cpy - - else: - splits_cpy = self.card_r.splits.copy() - for control in self.card_r.controls: - if control not in self.res_codes(): - index = self.card_r.controls.index(control) - split = self.card_r.splits[index] - try: - splits_cpy.remove(split) - except Exception: - print('aaaaaa') - - - punches = self.card_r.controls.copy() - splits = [] - for code in self.res_codes(): - if punches[0] == code: - splits.append(splits_cpy[0]) - splits_cpy.pop(0) - punches.pop(0) - continue - else: - splits.append(None) - return splits - - def asdict(self): - return { - 'id': self.id, - 'first': self.first, - 'last': self.last, - 'club_id': self.club_id, - 'club': self.club, - 'country': self.country, - 'card': self.card, - 'o_class_str': self.o_class_str, - 'fork' : self.fork, - 'start_time': self.start_time, - 'fee_id': self.fee_id - } - class CardDump: def __init__(self, card, controls, splits, read_time, s_time, f_time): self.card = card @@ -219,16 +155,6 @@ class CardDump: cards.append(CardDump(int(row[6]), controls, splits, read_time, s_time, f_time)) return cards - def asdict(self): - return { - 'card': self.card, - 'controls': self.controls, - 'splits': self.splits, - 'read_time': self.read_time.isoformat(), - 's_time': self.s_time.isoformat(), - 'f_time': self.f_time.isoformat() - } - # Stored in Event.courses class Course: def __init__(self, name, codes, forked=False, variations=None): @@ -241,14 +167,6 @@ class Course: def __repr__(self): return f'name({self.name})' - def asdict(self): - return { - 'name': self.name, - 'codes': self.codes, - 'forked': self.forked, - 'variations': self.variations - } - # Stored in Event.o_classes class OClass: def __init__(self, name, course): @@ -460,92 +378,6 @@ class Event: def create_result_pdf(self, file_path): pdf.create_result_list(copy.deepcopy(self), file_path) - def create_result_xml(self): - root = ET.Element('ResultList') - root.set('xmlns', 'http://www.orienteering.org/datastandard/3.0') - root.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance') - root.set('iofVersion', '3.0') - root.set('createTime', datetime.datetime.now().isoformat(timespec='seconds')) - root.set('creator', 'oTime') - root.set('status', 'Complete') - tree = ET.ElementTree(root) - event = ET.SubElement(root, 'Event') - xml_child(event, 'Id', self.id) - xml_child(event, 'Name', self.name) - for i in self.o_classes: - print('Hmmmmmm') - # - class_result = ET.SubElement(root, 'ClassResult') - # - t = ET.SubElement(class_result, 'Class') - xml_child(t, 'Name', i.name) - # - runners_same_c = get_runners_in_class(self.runners, i) - runners_ranked = rank_runners(runners_same_c, i) - # Put the OK runners first and Active last - runners_sorted = [i for i in runners_same_c if i not in runners_ranked] - runners_ranked.extend(runners_sorted) - - for n in runners_ranked: - person_result = ET.SubElement(class_result, 'PersonResult') - # - person = ET.SubElement(person_result, 'Person') - xml_child(person, 'Id', n.id) - # - name = ET.SubElement(person, 'Name') - xml_child(name, 'Family', n.last) - xml_child(name, 'Given', n.first) - # - # - # - org = ET.SubElement(person_result, 'Organisation') - xml_child(org, 'Id', n.club_id) - xml_child(org, 'Name', n.club) - country = ET.SubElement(org, 'Country') - # TODO: hent land fra løperobjektet - country.text = 'Norway' - country.set('code', 'NOR') - # - # - result = ET.SubElement(person_result, 'Result') - - # TODO: Dette bør skrives om til å bruke Runner metoder så mye som mulig. - if hasattr(n, 'card_r') and len(n.card_r.splits) > 2: - xml_child(result, 'StartTime', n.card_r.s_time.isoformat()) - xml_child(result, 'FinishTime', n.card_r.f_time.isoformat()) - xml_child(result, 'Time', n.totaltime()) - if n.status() == 'OK': - # - xml_child(result, 'TimeBehind', n.totaltime() - runners_ranked[0].totaltime()) - # - xml_child(result, 'Position', n.rank(self.runners)) - xml_child(result, 'Status', n.status()) - # - # TODO: ta utgangspunkt i løypa, ikke det brikka har stempla - for code, split in zip(n.card_r.controls, n.card_r.splits): - st = ET.SubElement(result, 'SplitTime') - xml_child(st, 'ControlCode', code) - xml_child(st, 'Time', split) - if code == n.res_codes()[-1]: - break - # - elif n.status() == 'Disqualified': - xml_child(result, 'Status', n.status()) - for code, split in zip(n.res_codes(), n.res_splits()): - st = ET.SubElement(result, 'SplitTime') - xml_child(st, 'ControlCode', code) - if split is not None: - xml_child(st, 'Time', split) - else: - xml_child(result, 'Status', n.status()) - else: - xml_child(result, 'Status', n.status()) - # - # - # - ET.indent(root, space=' ', level=0) - return tree - class Fee: def __init__(self, fee_id, name, currency, amount, from_birth_date=None, to_birth_date=None): @@ -556,16 +388,6 @@ class Fee: self.from_birth_date = from_birth_date self.to_birth_date = to_birth_date - def asdict(self): - return { - 'id': self.id, - 'name': self.name, - 'currency': self.currency, - 'amount': self.amount, - 'from_birth_date': self.from_birth_date, - 'to_birth_date': self.to_birth_date - } - def produce_class_result(event, o_class_name) -> ClassResult: o_class = event.get_o_class(o_class_name) runners = event.get_runners_in_o_class(o_class_name) @@ -614,96 +436,6 @@ def classes_from_ttime_conf(ttime_file, courses): loops += 1 return o_classes -def runners_from_xml_entries(xml_file): - tree = ET.parse(xml_file) - root = tree.getroot() - - url = '{http://www.orienteering.org/datastandard/3.0}' - runners = [] - person_entries = root.findall(f'./{url}PersonEntry') - for p_entry in person_entries: - - rid = p_entry[1][0].text - - person = p_entry.find(f'./{url}Person') - name = person.find(f'./{url}Name') - first = name.find(f'./{url}Given').text - last = name.find(f'./{url}Family').text - - organisation = p_entry.find(f'./{url}Organisation') - if organisation is not None: - club_id = organisation.find(f'./{url}Id').text - club_name = organisation.find(f'./{url}Name').text - club_name_short = organisation.find(f'./{url}ShortName').text - country = organisation.find(f'./{url}Country').attrib['code'] - else: - club_id = club_name = club_name_short = country = None - - class_el = p_entry.find(f'./{url}Class') - class_str = class_el.find(f'./{url}Name').text - - fee_id = int(p_entry.find(f'./{url}AssignedFee/{url}Fee/{url}Id').text) - - try: - card = int(p_entry.find(f'./{url}ControlCard').text) - except AttributeError: - card = None - - start_time = None - runners.append(Runner(rid, first, last, club=club_name, club_id=club_id, - country=country,card=card, o_class_str=class_str, - start_time=start_time, fee_id=fee_id)) - return runners - -def fees_from_xml_entries(xml_file): - tree = ET.parse(xml_file) - root = tree.getroot() - - url = '{http://www.orienteering.org/datastandard/3.0}' - allfees = root.findall(f'.//{url}Fee') - added_ids = [] - fee_objs = [] - for fee in allfees: - f_id = int(fee.find(f'./{url}Id').text) - if f_id not in added_ids: - added_ids.append(f_id) - - fee_id = f_id - name = fee.find(f'./{url}Name').text - currency = fee.find(f'./{url}Amount').attrib['currency'] - amount = int(fee.find(f'./{url}Amount').text) - try: - from_birth_date = fee.find(f'./{url}FromDateOfBirth').text - except AttributeError: - from_birth_date = None - try: - to_birth_date = fee.find(f'./{url}ToDateOfBirth').text - except AttributeError: - to_birth_date = None - - fee_objs.append(Fee(fee_id, name, currency, amount, - from_birth_date=from_birth_date, to_birth_date=to_birth_date)) - return fee_objs - -def courses_from_xml(xml_file): - tree = ET.parse(xml_file) - root = tree.getroot() - - url = '{http://www.orienteering.org/datastandard/3.0}' - allcourses = root.findall(f'.//{url}Course') - courseobjs = [] - for c in allcourses: - name = c.find(f'./{url}Name').text - controls = [] - allcontrols = c.findall(f'./{url}CourseControl') - for n in allcontrols: - controls.append(n.find(f'./{url}Control').text) - controls.remove('STA1') - controls.remove('FIN1') - controls = [int(l) for l in controls] - courseobjs.append(Course(name, controls)) - return courseobjs - # Checks if small list is in big list def contains(small, big): valid = True @@ -720,19 +452,4 @@ def contains(small, big): if valid: return map_bl else: - return False - -def rank_runners(allrunners, o_class): - runners = get_runners_in_class(allrunners, o_class) - runners_ranked = [] - for i in runners: - if i.status() == 'OK': - runners_ranked.append(i) - runners_ranked.sort(key=lambda x: x.totaltime()) - return runners_ranked - - -# Used to make creating xml files easier -def xml_child(parent, tag, content): - e = ET.SubElement(parent, tag) - e.text = str(content) \ No newline at end of file + return False \ No newline at end of file