471,354 Members | 2,134 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,354 software developers and data experts.

Advice for editing xml file using ElementTree and wxPython

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>

I've been playing around with parsing that file using the ElementTree
functions, and writing little functions to walk the tree and print
stuff out. I'd like to construct a little wxPython program to modify
the values graphically, maybe using something like a TreeCtrl widget.
I'm pretty sure I can figure out how to get the data into the widget.

- Struct
- File Name: water
- Number of Atoms: 3

etc.

What's confusing me is what I do when I shut down the gui and save the
data back to a file. What I would like to be able to do is to update
the values in the ElementTree itself, and use the .write(file)
function of the elementtree to write out the file, since that ends up
printing out something pretty much identical to the original xml file.
If I want to do this, it seems like I need to keep a connection
between the gui element and the original value in the elementtree, so
I can update it. But I'm having a hard time visualizing exactly how
this works. Can someone help me out here a bit?

If this is impossible, or too difficult, I can certainly figure out a
way to dump the XML directly from the gui itself, but I worry that
I'll mangle the XML in the process, which elementtree doesn't do (i.e.
the null operation, parsing a file with elementtree and writing it out
again doesn't change anything).

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.

Thanks in advance for your time,

Rick
Dec 9 '07 #1
2 4109
On Dec 8, 8:35 pm, Rick Muller <rpmul...@gmail.comwrote:
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()
Dec 9 '07 #2
On Dec 8, 11:57 pm, Waldemar Osuch <waldemar.os...@gmail.comwrote:
On Dec 8, 8:35 pm, Rick Muller <rpmul...@gmail.comwrote:
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()
This was exactly what I was looking for! Thanks very much.

Rick
Dec 9 '07 #3

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

7 posts views Thread by Stewart Midwinter | last post: by
14 posts views Thread by Erik Bethke | last post: by
3 posts views Thread by dlesandrini | last post: by
2 posts views Thread by mirandacascade | last post: by
8 posts views Thread by D | last post: by
reply views Thread by limodou | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.