Sunday, October 24, 2010

PyXTree - pyGTK TreeView ElementTree XML Viewer

PyXTree is a minimal python xml viewer.

Written in python (download), pyxtree uses the treeview and scrolledwindow controls from the pyGTK download) UI, together with the ElementTree xml library that is included in the python standard library.



# --- --- --- --- --- --- --- --- --- --- --- ---
from optparse import OptionParser
# pyGTK --- --- --- --- --- --- --- --- ---
import pygtk
pygtk.require('2.0')
import gtk
# ElementTree - --- --- --- --- --- --- ---
import xml.etree.ElementTree as ET
# --- --- --- --- --- --- --- --- --- --- --- ---
import sys

xml_2_ns = {
'http://www.s3.org/XML/1998/namespace' : 'xml',
}

ns_2_xml = {
'xml' : 'http://www.s3.org/XML/1998/namespace',
}

def extend_tree(treestore, element, parent_node, ns_list):
'''
'''

#import pdb; pdb.set_trace()

node_label = '%s' % strip_ns_from_str(element.tag, ns_list)

if element.text != None:
element_text = element.text.strip()
if (len(element_text) > 0):
element_text = strip_ns_from_str(element_text, ns_list)
#discard = treestore.append(node, [element_text])
node_label = 'e %s : %s' % (node_label, element_text)

node = treestore.append(parent_node, [node_label])

# add attribute name/val pairs to node
for name, value in element.items():
name = strip_ns_from_str(name, ns_list)
value = strip_ns_from_str(value, ns_list)
label = 'a %s = %s' % (name, value)
treestore.append(node, [label])

# recurse over children
for child_element in element.getchildren():
child_node = extend_tree(treestore, child_element, node, ns_list)

return node

def etree_to_gtk_treestore(tree):
'''
construct gtk.TreeStore(str) from ElementTree
'''
treestore = gtk.TreeStore(str)

ns_list = ns_list_from_tree(tree)

element = tree.getroot()

node_label = '%s' % strip_ns_from_str(element.tag, ns_list)

if element.text != None:
element_text = element.text.strip()
if (len(element_text) > 0):
element_text = strip_ns_from_str(element_text, ns_list)
node_label = 'e %s : %s' % (node_label, element_text)

node = treestore.append(None, [node_label])

for child_e in element.getchildren():
extend_tree(treestore, child_e, node, ns_list)

# add attribute name/val pairs to node
for name, value in element.items():
name = strip_ns_from_str(name, ns_list)
value = strip_ns_from_str(value, ns_list)
label = '%s = %s' % (name, value)
treestore.append(None, [label])

# if ns is global
for ns in ns_list:
label = 'xmlns : %s' % ns
treestore.append(None, [label])

return treestore

def ns_from_string(s):
left = s.find('{')
right = s.find('}')
ns = s[left+1:right]
return ns

def process_potential_ns_string(s, ns_list):

if s == None:
return

if (s.find('{') != -1) and (s.find('}') != -1):
ns = ns_from_string(s)
if (ns not in ns_list):
ns_list.append(ns)

def ns_list_from_element(el, ns_list):

# tag
process_potential_ns_string(el.tag, ns_list)
# text
process_potential_ns_string(el.text, ns_list)

# attributes
for name, value in el.items():
process_potential_ns_string(name, ns_list)
process_potential_ns_string(value, ns_list)

for child_el in el.getchildren():
ns_list_from_element(child_el, ns_list)

return ns_list

def ns_list_from_tree(etree):
'''
'''
ns_list = []
root_e = etree.getroot()

# tag
process_potential_ns_string(root_e.tag, ns_list)
# text
process_potential_ns_string(root_e.text, ns_list)

# attributes
for name, value in root_e.items():
process_potential_ns_string(name, ns_list)
process_potential_ns_string(value, ns_list)

# child elements
for child_el in root_e.getchildren():
ns_list_from_element(child_el, ns_list)

return ns_list

def strip_ns_from_str(s, ns_list):
stripped = str(s)
for ns in ns_list:
token = '{%s}' % ns
loc = stripped.find(token)
if (loc != -1):
stripped = stripped[:loc] + stripped[loc + len(token):len(stripped)]

return stripped

class XMLTreeView:
'''
'''
def delete_event(widget, event, data=None):
'''
not an instance method, cuz gtk will not call as such
'''
gtk.main_quit()
return False

def __init__(self, path, title='pyxtree - python XML tree viewer', xsize=900, ysize = 500):
'''
'''
etree = ET.parse(path)
self.treestore = etree_to_gtk_treestore(etree)

self.window = gtk.Dialog()
self.window.connect("destroy", self.delete_event)
self.window.set_border_width(0)

self.swin_tree = gtk.ScrolledWindow()
self.swin_tree.set_border_width(10)
self.swin_tree.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
self.window.vbox.pack_start(self.swin_tree, True, True, 0)

self.swin_text = gtk.ScrolledWindow()
self.swin_text.set_border_width(10)
self.swin_text.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
self.window.vbox.pack_start(self.swin_text, True, True, 0)

self.window.set_title(title)
self.window.set_size_request(xsize, ysize)
self.window.connect("delete_event", self.delete_event)

# create the TreeView using treestore
self.treeview = gtk.TreeView(self.treestore)
self.tvcolumn = gtk.TreeViewColumn(path)
self.treeview.append_column(self.tvcolumn)
self.cell = gtk.CellRendererText()
# add the cell to the tvcolumn and allow it to expand
self.tvcolumn.pack_start(self.cell, True)
# set the cell "text" attribute to column 0 - retrieve text
# from that column in treestore
self.tvcolumn.add_attribute(self.cell, 'text', 0)
# make it searchable
self.treeview.set_search_column(0)
# Allow sorting on the column
#self.tvcolumn.set_sort_column_id(0)
# Allow drag and drop reordering of rows
#self.treeview.set_reorderable(True)

self.swin_tree.add_with_viewport(self.treeview)
self.swin_tree.show()

xfile = open(path, 'r')
xtext = xfile.read()
xfile.close()

label = gtk.Label(xtext)

# ns_list = ns_list_from_tree(etree)

# ns_str = ''
# for ns in ns_list:
# ns_str = ns_str + str(ns) + '\n'

# label = gtk.Label(ns_str)

label.set_alignment(xalign=0, yalign=0.5)

self.swin_text.add_with_viewport(label)
self.swin_text.show()

self.window.show_all()

def main(path = None):
'''
'''
if (path == None):

filechooser = gtk.FileChooserDialog(
title=None,
action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))

filter_stdxmlfiles = gtk.FileFilter()
filter_stdxmlfiles.set_name("Std XML Files")
filter_stdxmlfiles.add_pattern("*.xml")
filter_stdxmlfiles.add_pattern("*.wsdl")
filechooser.add_filter(filter_stdxmlfiles)

filter_allfiles = gtk.FileFilter()
filter_allfiles.set_name("All files")
filter_allfiles.add_pattern("*")
filechooser.add_filter(filter_allfiles)

response = filechooser.run()

if response == gtk.RESPONSE_OK:
path = filechooser.get_filename()
elif response == gtk.RESPONSE_CANCEL:
pass
#log failure

filechooser.destroy()

if (path != None):
tree_view = XMLTreeView(path)
gtk.main()
return

def src_file_from_cmd_args(args):
'''
'''
akapy = [
'pyxtree',
'pyxtree.py',
'python',
'python.exe',
'python2.5',
'python25.exe',
]
cleaned = []
for arg in args:
washed = arg.strip().lower()
if (washed not in akapy) and (washed.find('python') == -1):
cleaned.append(washed)
if len(cleaned) == 0:
cleaned = [None]
return cleaned

def configure_logging(LOG_FILENAME='pyxtree.log'):
import logging
logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO)
log = logging.getLogger()
return log


def setup_command_line_options():
'''
using optparse
define command line arguments
return target filename, None if none specified
'''
parser = OptionParser()
parser.add_option('-f', dest='filename', help='target xml file to view')
(options, args) = parser.parse_args()
return(options.filename)

if __name__ == "__main__":

print('\nPyXTree - david.barkhuizen@gmail.com')
print('help: pyxtree -h\n')

xmlfilepath = setup_command_line_options()

log = configure_logging()

log.info('target file specified at command line = %s' % xmlfilepath)
main(path=xmlfilepath)

No comments:

Post a Comment

comment: