Frank Millman wrote: > "Frank Millman" wrote in message news:nplvvl$ci2$1...@blaine.gmane.org... > >> Hi all > >> I have mentioned in the past that I use XML for storing certain >> structures 'off-line', and I got a number of comments urging me to use >> JSON or YAML instead. > >> Can anyone offer an alternative which is closer to my original intention? > > Thanks to Chris and Peter for their additional input - much appreciated. > > At the risk of disappointing some of you, this is how I am going to > proceed.
'Tis too late for me to stop ;) > 1. I am writing tools to make it easier to develop business systems, and > at the same time I am developing a business system. As the tools mature I > am spending more time on the system, but as I work on the system I am > finding shortcomings in the tools, so I am bouncing between the two at the > moment. > > 2. There are many areas of the tools which other users will find confusing > at first and will require explanations and documentation. I am more than > ready to make changes based on the reactions I get. The subject of this > thread is one small part of this. > > 3. My immediate priority is to finish the business system, get it out > there, and get feedback. Hopefully other users will then start dabbling > with the tools and provide feedback there as well. > > 4. As I have said already, for good or ill, I am comfortable with my > current use of XML, so I do not have a pressing need to change to anything > else. The problem that prompted this thread was the issue of storing '<' > and '>' in attributes. I have come up with a simple workaround - pass the > XML through a > function between the database and the gui, converting from '>' to '>' > in one direction, and back to '>' in the other. It works. As you have to keep the "<", why bother? > 5. I have learned a lot from this thread, but for now it is staying in the > back of my mind. If I ever get my project to the point where I need to > move it to the front, I will know that I am getting somewhere! At that point you may also look at my messy/buggy/incomplete attempt to convert between xml and python: $ cat convert.py import ast from xml.etree import ElementTree as etree XML = """\ <case> <compare src="_param.auto_party_id" op="is_not" tgt="$None"> <case> <on_insert> <auto_gen args="_param.auto_party_id"/> </on_insert> <not_exists> <literal value="<new>"/> </not_exists> </case> </compare> </case> """ tree = etree.fromstring(XML) TARGETS = { "$None": "None", } RTARGETS = { None: "$None", } assert len(RTARGETS) == len(TARGETS) OPS = { "is_not": "is not", } ROPS = {ast.IsNot: "is_not"} assert len(ROPS) == len(OPS) NAMES = {"on_insert", "not_exists"} FUNCS = {"auto_gen"} def getchildren(elem): yield from elem.getchildren() def to_python(elem, indent=""): # XXX build an AST rather than source code. if elem.tag == "compare": yield "{}if {} {} {}:".format( indent, elem.attrib["src"], OPS[elem.attrib["op"]], TARGETS[elem.attrib["tgt"]] ) [child] = getchildren(elem) yield from to_python(child, indent) elif elem.tag in NAMES: yield "{}if {}:".format(indent, elem.tag) for child in getchildren(elem): yield from to_python(child, indent + " ") elif elem.tag == "case": for child in getchildren(elem): yield from to_python(child, indent + " ") elif elem.tag == "literal": yield "{}value = {!r}".format(indent, elem.attrib["value"]) elif elem.tag in FUNCS: yield "{}auto_gen({})".format(indent, elem.attrib["args"]) else: raise ValueError("Unknown tag {!r}".format(elem.tag)) def dotted(node): if isinstance(node, ast.Attribute): return dotted(node.value) + "." + node.attr else: return node.id def to_xml(python): module = ast.parse(python) [body] = module.body root = etree.Element("case") def _convert(node, parent): if isinstance(node, ast.If): test = node.test if isinstance(test, ast.Compare): compare = etree.Element("compare") [op] = test.ops compare.attrib["src"] = dotted(test.left) compare.attrib["op"] = ROPS[type(op)] right = test.comparators[0].value compare.attrib["tgt"] = RTARGETS[right] case = etree.Element("case") compare.append(case) parent.append(compare) for child in node.body: _convert(child, case) elif isinstance(test, ast.Name): ename = etree.Element(test.id) parent.append(ename) for child in node.body: _convert(child, ename) elif isinstance(node, ast.Expr): evalue = node.value evalue.func.id invoke = etree.Element(evalue.func.id) invoke.attrib["args"] = dotted(evalue.args[0]) parent.append(invoke) elif isinstance(node, ast.Assign): assign = etree.Element("literal") [target] = node.targets assign.attrib["value"] = node.value.s parent.append(assign) else: global x x = node exit("unhandled") _convert(body, root) return root # http://stackoverflow.com/questions/17402323/ # use-xml-etree-elementtree-to-write-out-nicely-formatted-xml-files ElementTree = etree from xml.dom import minidom def prettify(elem): """Return a pretty-printed XML string for the Element. """ rough_string = ElementTree.tostring(elem, 'utf-8') reparsed = minidom.parseString(rough_string) return reparsed.toprettyxml(indent=" ") print("XML...") print(XML) print("\nbecomes Python...") python = "\n".join(to_python(next(getchildren(tree)))) print(python) print("\nbecomes XML:") root = to_xml(python) print(prettify(root)) $ python3 convert.py XML... <case> <compare src="_param.auto_party_id" op="is_not" tgt="$None"> <case> <on_insert> <auto_gen args="_param.auto_party_id"/> </on_insert> <not_exists> <literal value="<new>"/> </not_exists> </case> </compare> </case> becomes Python... if _param.auto_party_id is not None: if on_insert: auto_gen(_param.auto_party_id) if not_exists: value = '<new>' becomes XML: <?xml version="1.0" ?> <case> <compare op="is_not" src="_param.auto_party_id" tgt="$None"> <case> <on_insert> <auto_gen args="_param.auto_party_id"/> </on_insert> <not_exists> <literal value="<new>"/> </not_exists> </case> </compare> </case> -- https://mail.python.org/mailman/listinfo/python-list