snippetpythonMinor
Convert elementtree to dict
Viewed 0 times
convertdictelementtree
Problem
Just needed a quick way to convert an elementtree element to a dict. I don't care if attributes/elements clash in name, nor namespaces. The XML files are small enough. If an element has multiple children which have the same name, create a list out of them:
Thoughts? I'm particularly un-fond of the
def elementtree_to_dict(element):
d = dict()
if hasattr(element, 'text') and element.text is not None:
d['text'] = element.text
d.update(element.items()) # element's attributes
for c in list(element): # element's children
if c.tag not in d:
d[c.tag] = elementtree_to_dict(c)
# an element with the same tag was already in the dict
else:
# if it's not a list already, convert it to a list and append
if not isinstance(d[c.tag], list):
d[c.tag] = [d[c.tag], elementtree_to_dict(c)]
# append to the list
else:
d[c.tag].append(elementtree_to_dict(c))
return dThoughts? I'm particularly un-fond of the
not instance part of the last if.Solution
def elementtree_to_dict(element):
d = dict()I'd avoid the name
d its not very helpfulif hasattr(element, 'text') and element.text is not None:
d['text'] = element.textgetattr has a third parameter, default. That should allow you to simplify this piece of code a bitd.update(element.items()) # element's attributes
for c in list(element): # element's childrenThe
list does nothing, except waste memory.if c.tag not in d:
d[c.tag] = elementtree_to_dict(c)
# an element with the same tag was already in the dict
else:
# if it's not a list already, convert it to a list and append
if not isinstance(d[c.tag], list):
d[c.tag] = [d[c.tag], elementtree_to_dict(c)]
# append to the list
else:
d[c.tag].append(elementtree_to_dict(c))Yeah this whole block is a mess. Two notes:
- Put everything in lists to begin with, and then take them out at the end
-
call
elementtree_to_dict oncereturn dThis whole piece of code looks like a bad idea.
Becomes
{"bar" : {"id": 42}}Whereas
Becomes
{"bar" : [{"id" : 42}, {"id": 36}]}The XML schema is the same, but the python "schema" will be different. It'll be annoying writing code that correctly handles both of these cases.
Having said that, here's my cleanup of your code:
def elementtree_to_dict(element):
node = dict()
text = getattr(element, 'text', None)
if text is not None:
node['text'] = text
node.update(element.items()) # element's attributes
child_nodes = {}
for child in element: # element's children
child_nodes.setdefault(child, []).append( elementtree_to_dict(child) )
# convert all single-element lists into non-lists
for key, value in child_nodes.items():
if len(value) == 1:
child_nodes[key] = value[0]
node.update(child_nodes.items())
return nodeCode Snippets
def elementtree_to_dict(element):
d = dict()if hasattr(element, 'text') and element.text is not None:
d['text'] = element.textd.update(element.items()) # element's attributes
for c in list(element): # element's childrenif c.tag not in d:
d[c.tag] = elementtree_to_dict(c)
# an element with the same tag was already in the dict
else:
# if it's not a list already, convert it to a list and append
if not isinstance(d[c.tag], list):
d[c.tag] = [d[c.tag], elementtree_to_dict(c)]
# append to the list
else:
d[c.tag].append(elementtree_to_dict(c))<foo>
<bar id="42"/>
</foo>Context
StackExchange Code Review Q#10400, answer score: 7
Revisions (0)
No revisions yet.