Advice for editing xml file using ElementTree and wxPython

Waldemar Osuch waldemar.osuch at gmail.com
Sun Dec 9 01:57:41 EST 2007


On Dec 8, 8:35 pm, Rick Muller <rpmul... at gmail.com> wrote:
> I'm a computational chemist who frequently dabbles in Python. A
> collaborator sent me a huge XML file that at one point was evidently
> modified by a now defunct java application. A sample of this file
> looks something like:
>
> <group type="struct">
>     <name>Test</name>
>     <param type="string">
>         <name>File Name</name>
>         <cTag>fileName</cTag>
>         <desc>Name of the input file</desc>
>         <value>water</value>
>     </param>
>     <param type="int">
>         <name>Number of Atoms</name>
>         <cTag>natoms</cTag>
>         <desc>Number of atoms in the molecule</desc>
>         <value>3</value>
>     </param>
> </group>
>

<snip>

>
> Seems like this is something that's probably pretty common, modifying
> a data structure using a gui, so I'm hoping that someone has thought
> about this and has some good advice about best practices here.
>

The trick is to keep a reference to the actual ElementTree objects
as you build your TreeCtrl.  Ability to store arbitrary Python object
in the TreeCtrl Item makes it easy.  In an event handler modify the
original element and you are done.  Do not forget to save when
closing.

If the XML file is very large you may have performance issues since
the whole parsed tree is kept in memory.  Luckily the ElementTree
representation is lean.

A sample below shows the approach.  It is very basic but I hope it
conveys the idea.  Please note that edits to the actual tags are
ignored.

-------------------------------------------------------------------
import wx
import xml.etree.cElementTree as ET

class MainFrame(wx.Frame):
    def __init__(self, fpath):
        wx.Frame.__init__(self, None)
        self.fpath = fpath
        self.xml = ET.parse(fpath)
        self.tree = wx.TreeCtrl(self,
            style=wx.TR_HAS_BUTTONS|wx.TR_EDIT_LABELS)
        root = self.fillmeup()
        self.tree.Expand(root)

        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEdit)

    def fillmeup(self):
        xml = self.xml.getroot()
        tree = self.tree
        root = tree.AddRoot(xml.tag)
        def add(parent, elem):
            for e in elem:
                item = tree.AppendItem(parent, e.tag, data=None)
                text = e.text.strip()
                if text:
                    val = tree.AppendItem(item, text)
                    tree.SetPyData(val, e)
                add(item, e)
        add(root, xml)
        return root

    def OnEdit(self, evt):
        elm = self.tree.GetPyData(evt.Item)
        if elm is not None:
            elm.text = evt.Label

    def OnClose(self, evt):
        self.xml.write(self.fpath)
        self.Destroy()


if __name__=='__main__':
    app = wx.App(False)
    frame = MainFrame('sample.xml')
    frame.Show()
    app.MainLoop()





More information about the Python-list mailing list