Editing XML as a dictionary in python?

This'll get you a dict minus attributes. I don't know, if this is useful to anyone. I was looking for an xml to dict solution myself, when I came up with this.


      
import xml.etree.ElementTree as etree

tree = etree.parse('test.xml')
root = tree.getroot()

def xml_to_dict(el):
  d={}
  if el.text:
    d[el.tag] = el.text
  else:
    d[el.tag] = {}
  children = el.getchildren()
  if children:
    d[el.tag] = map(xml_to_dict, children)
  return d

This: http://www.w3schools.com/XML/note.xml

<note>
 <to>Tove</to>
 <from>Jani</from>
 <heading>Reminder</heading>
 <body>Don't forget me this weekend!</body>
</note>

Would equal this:


{'note': [{'to': 'Tove'},
          {'from': 'Jani'},
          {'heading': 'Reminder'},
          {'body': "Don't forget me this weekend!"}]}

I'm not sure if converting the info set to nested dicts first is easier. Using ElementTree, you can do this:

import xml.etree.ElementTree as ET
doc = ET.parse("template.xml")
lvl1 = doc.findall("level1-name")[0]
lvl1.remove(lvl1.find("leaf1")
lvl1.remove(lvl1.find("leaf2")
# or use del lvl1[idx]
doc.write("config-new.xml")

ElementTree was designed so that you don't have to convert your XML trees to lists and attributes first, since it uses exactly that internally.

It also support as small subset of XPath.


For easy manipulation of XML in python, I like the Beautiful Soup library. It works something like this:

Sample XML File:

<root>
  <level1>leaf1</level1>
  <level2>leaf2</level2>
</root>

Python code:

from BeautifulSoup import BeautifulStoneSoup, Tag, NavigableString

soup = BeautifulStoneSoup('config-template.xml') # get the parser for the xml file
soup.contents[0].name
# u'root'

You can use the node names as methods:

soup.root.contents[0].name
# u'level1'

It is also possible to use regexes:

import re
tags_starting_with_level = soup.findAll(re.compile('^level'))
for tag in tags_starting_with_level: print tag.name
# level1
# level2

Adding and inserting new nodes is pretty straightforward:

# build and insert a new level with a new leaf
level3 = Tag(soup, 'level3')
level3.insert(0, NavigableString('leaf3')
soup.root.insert(2, level3)

print soup.prettify()
# <root>
#  <level1>
#   leaf1
#  </level1>
#  <level2>
#   leaf2
#  </level2>
#  <level3>
#   leaf3
#  </level3>
# </root>