from argparse import ArgumentParser from csv import reader as csv_reader from pprint import pformat from xml.dom.minidom import parseString as xml_parser from xml.etree import ElementTree class System: """Represents an L-System""" def __init__( self, name: str, base: list[str], axiom: str, substitutions: list[tuple[str, str]], interpretations: list[tuple[str, str]], ): self.name = name """System name""" self.base = base """Set used""" self.axiom = axiom """Axiom used at the start of iterations""" self.substitutions = substitutions """ Substitution for each member of the base, represented as a couple (member, substitution) """ self.interpretations = interpretations """ Interpretation for each member of the base, represented as a couple (member, interpretation) """ # Interpretation of extra symbols added if necessary extra_symbols = ["[", "]"] for _, substitution in substitutions: if any(symbol in substitution for symbol in extra_symbols): self.interpretations.extend( [(extra_symbols[0], "STORE"), (extra_symbols[1], "RESTORE")] ) break def __repr__(self): return pformat(self.__dict__, compact=True, width=120, sort_dicts=False) def to_xml(self) -> ElementTree.Element: """Convert the current system into an XML element""" system = ElementTree.Element("lsystem") base = ElementTree.SubElement(system, "base") base.text = "".join(self.base) axiom = ElementTree.SubElement(system, "axiom") axiom.text = self.axiom substitutions = ElementTree.SubElement(system, "substitutions") for member, substitution in self.substitutions: sub_element = ElementTree.SubElement(substitutions, "substitution") sub_element.set("member", member) sub_element.text = substitution interpretations = ElementTree.SubElement(system, "interpretations") for member, interpretation in self.interpretations: inter_element = ElementTree.SubElement(interpretations, "interpretation") inter_element.set("member", member) inter_element.text = interpretation return system def data_reader(path: str, delimiter: str = ","): """Read a CSV file and returns a list of L-System""" res: list[System] = [] with open(path) as csv_file: data = csv_reader(csv_file, delimiter=delimiter) for system in data: name = system[0] base = list(system[1]) axiom = system[2] substitutions = [(v, system[3 + i]) for i, v in enumerate(base)] interpretations = [ (v, system[3 + i + len(substitutions)]) for i, v in enumerate(base) ] res.append(System(name, base, axiom, substitutions, interpretations)) return res def lsystems_xml(systems: list[System]) -> ElementTree.Element: """Convert list of L-system structure into XML""" root = ElementTree.Element("lsystems") for system in systems: root.append(system.to_xml()) return root if __name__ == "__main__": parser = ArgumentParser(description="Generate XML representation of L-systems") parser.add_argument( "file", metavar="FILE", help="CSV file containing L-system data" ) parser.add_argument( "-o", "--output", metavar="OUTPUT_FILE", help="Specify output file for XML" ) args = parser.parse_args() # Read data lsystems = data_reader(args.file) # Generate XML xml = lsystems_xml(lsystems) # Output XML dom = xml_parser(ElementTree.tostring(xml)) pretty_xml = dom.toprettyxml(encoding="UTF-8").decode() if args.output: with open(args.output, "w") as output_file: output_file.write(pretty_xml) else: print(pretty_xml)