Alternatives to XML?
Peter Otten
__peter__ at web.de
Thu Aug 25 09:58:24 EDT 2016
Frank Millman wrote:
> "Frank Millman" wrote in message news:nplvvl$ci2$1 at 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>
More information about the Python-list
mailing list