Welcome, guest | Sign In | My Account | Store | Cart
# Author: Miguel Martinez Lopez
#
# Uncomment the next line to see my email
# print("Author's email: %s"%"61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))

try:
    from ttk import Treeview, Scrollbar, Frame
    from Tkconstants import HORIZONTAL, VERTICAL, N,S,E,W, END
except ImportError:
    from tkinter.ttk import Treeview, Scrollbar, Frame
    from tkinter.constants import HORIZONTAL, VERTICAL, N,S,E,W, END
    
import xml.etree.ElementTree as ET

from operator import attrgetter


def autoscroll(sbar, first, last):
    """Hide and show scrollbar as needed."""
    first, last = float(first), float(last)
    if first <= 0 and last >= 1:
        sbar.grid_remove()
    else:
        sbar.grid()
    sbar.set(first, last)


class XML_Viwer(Frame):

    def __init__(self, master, xml=None, **kwargs):
        Frame.__init__(self, master, class_="XML_Viwer")

        self._vsb = Scrollbar(self, orient=VERTICAL)
        self._hsb = Scrollbar(self, orient=HORIZONTAL)

        kwargs["yscrollcommand"] = lambda f, l: autoscroll(self._vsb, f, l)
        kwargs["xscrollcommand"] = lambda f, l: autoscroll(self._hsb, f, l)
        
        self._treeview = Treeview(self, **kwargs)
        
        # Without this line, horizontal scrolling doesn't work properly.
        self._treeview.column("#0", stretch= False)

        self._vsb['command'] = self._treeview.yview
        self._hsb['command'] = self._treeview.xview

        self._treeview.grid(column=0, row=0, sticky=N+S+W+E)
        self._vsb.grid(column=1, row=0, sticky=N+S)
        self._hsb.grid(column=0, row=1, sticky=E+W)
        
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self._element_tree = None

        if xml is not None:
            self.parse_xml(xml)

    def parse_xml(self, xml):
        self._element_tree = ET.ElementTree(ET.fromstring(xml))
        
        self.clear()
        self._walk_xml(self._element_tree.getroot())
        
    @property
    def element_tree(self):
        return self._element_tree
    
    @element_tree.setter
    def element_tree(self, element_tree):
        self._element_tree = element_tree
        
        self.clear()
        self._walk_xml(element_tree.getroot())   
        
    def clear(self):
        self._treeview.delete(*self._treeview.get_children())

    def _walk_xml(self, node, depth=0, parent=""):
        text = "<" + node.tag

        attrs = node.attrib
        
        # list function is here necessary to provide support to Python 3
        a_names = list(attrs.keys())
        a_names.sort()

        for a_name in a_names:
            text += ' %s="' % a_name
            text += attrs[a_name]
            text += '"'

        text += ">"
        item = self._treeview.insert(parent, END, text = text)
        
        if node.text:
            text = node.text.strip()
            if text != "":
                for line in text.splitlines():
                    self._treeview.insert(item, END, text = line)

        child_nodes = sorted(list(node), key=attrgetter('tag'))
        for child_node in node:
            self._walk_xml(child_node, depth+1, parent=item)

        
        if node.tail:
            tail = node.tail.strip()
            if tail != "":
                for line in tail.splitlines():
                    self._treeview.insert(parent, END, text = line)

if __name__ == "__main__":
    try:
        from Tkinter import Tk
    except ImportError:
        from tkinter import Tk
    
    root = Tk()
    xml = """
    <messages>
      <note id="501">
        <to>Tove</to>
        <from>Jani</from>
        <heading>Reminder</heading>
        <body>Don't forget me this weekend!</body>
      </note>
      <note id="502">
        <to>Jani</to>
        <from>Tove</from>
        <heading>Re: Reminder</heading>
        <body>I will not</body>
      </note>
    </messages>"""
    XML_Viwer(root, xml).pack()
    root.mainloop()

Diff to Previous Revision

--- revision 1 2017-01-28 00:17:12
+++ revision 2 2017-01-28 00:23:25
@@ -80,7 +80,9 @@
         text = "<" + node.tag
 
         attrs = node.attrib
-        a_names = attrs.keys()
+        
+        # list function is here necessary to provide support to Python 3
+        a_names = list(attrs.keys())
         a_names.sort()
 
         for a_name in a_names:
@@ -106,7 +108,7 @@
             tail = node.tail.strip()
             if tail != "":
                 for line in tail.splitlines():
-                    self._treeview.insert(item, END, text = line)
+                    self._treeview.insert(parent, END, text = line)
 
 if __name__ == "__main__":
     try:

History