#!/usr/bin/env python # vim: ts=8 sts=4 sw=4 expandtab # Author: Douglas Clowes (dcl@ansto.gov.au) 2014-04-24 # """ This is a SICS hipadaba module. It allows for loading the gumtree XML obtained from SICS and accessing the tree by path to obtain the children and properties of a node on a named path. """ # # Try to import an ElementTree compatible XML library in the order # of our preference (performance) but fall back to a default version. # try: from lxml import etree print("running with lxml.etree") except ImportError: try: # Python 2.5 import xml.etree.cElementTree as etree print("running with cElementTree on Python 2.5+") except ImportError: try: # Python 2.5 import xml.etree.ElementTree as etree print("running with ElementTree on Python 2.5+") except ImportError: try: # normal cElementTree install import cElementTree as etree print("running with cElementTree") except ImportError: try: # normal ElementTree install import elementtree.ElementTree as etree print("running with ElementTree") except ImportError: print("Failed to import ElementTree from any known place") class HipadabaTree(object): """Hipadaba Tree Class """ def __init__(self, from_this): """Build a Hipadaba Tree object from an 'ElementTree' object Parameters ---------- from_this : XML-like ElementTree compatible object, or string or array of strings """ if isinstance(from_this, list) and isinstance(from_this[0], str): root = etree.fromstringlist(from_this) elif isinstance(from_this, str): if len(from_this) > 0: if from_this[0] == "<": root = etree.fromstring(from_this) elif from_this[0] == "@": root = etree.parse(from_this[1:]) elif from_this.lower().endswith(".xml"): root = etree.parse(from_this) else: raise Exception("unknown string") else: raise Exception("short string") else: directory = dir(from_this) if "findall" not in directory: raise Exception("findall not in object") if "find" not in directory: raise Exception("find not in object") root = from_this self.root = root def short_tree(self, tree=None): """ """ if tree is None: tree = self.root if isinstance(tree, type(self.root)): tree_part = {"name": ""} else: tree_part = {"name": tree.attrib['id']} tree_part["children"] = [ch.attrib['id'] for ch in tree.findall('component')] tree_part["properties"] = [ch.attrib['id'] for ch in tree.findall('property')] return tree_part def find_path(self, path, tree=None): debug = True if tree is None: tree = self.root if debug: print "Looking for %s in %s" % (repr(path), self.short_tree(tree)) path_list = [p for p in path.lower().strip('/').split('/') if p is not ''] if path_list == ['']: if debug: print "Finding root: %s in %s" % (repr(path_list), self.short_tree(tree)) return tree child = tree for node in path_list: children = [ch for ch in child.findall('component') if ch.attrib['id'].lower() == node.lower()] if len(children) == 0: if debug: print "Not found: %s in %s" % (repr(path_list), self.short_tree(tree)) return None child = children[0] if debug: print "Finding node: %s in %s" % (repr(path_list), self.short_tree(child)) return child def list_tree(self, tree=None, props=False, indent=0): if tree is None: tree = self.root text = [] if isinstance(tree, type(self.root)): text += [' '*indent + '* ' + ''] else: text += [' '*indent + '* ' + tree.attrib['id']] if props: properties = sorted(tree.findall('property'), key=lambda node: node.attrib['id'].lower()) for prop in properties: line = ' '*indent + ' - ' + prop.attrib['id'] + '=' items = [ch.text for ch in prop.findall('value') if ch.text is not None] line += ' '.join(items) text += [line] children = sorted(tree.findall('component'), key=lambda node: node.attrib['id'].lower()) for child in children: text += self.list_tree(child, props, indent+1) return text def print_tree(self, tree=None, props=False, indent=0): for line in self.list_tree(tree, props, indent): print line def getNode(self, path, tree=None): return self.find_path(path, tree) def getProperty(self, path, property, tree=None): node = self.find_path(path, tree) if node is None: return None items = [ch for ch in node.findall('property') if ch.attrib['id'].lower() == property.lower()] if len(items) == 0: return None node = items[0] items = [ch.text for ch in node.findall('value') if ch.text is not None] if len(items) == 0: return "" return ' '.join(items) def getProperties(self, path, tree=None): node = self.find_path(path, tree) if node is not None: return sorted([ch.attrib['id'] for ch in node.findall('property')]) return None def getChildren(self, path, tree=None): node = self.find_path(path, tree) if node: return sorted([ch.attrib['id'] for ch in node.findall('component')]) return None if __name__ == "__main__": filename = "junk.xml" fd = open(filename, "r") lines = fd.readlines() print "From file:", HipadabaTree(filename).short_tree() print "From list:", HipadabaTree(lines).short_tree() print "From text:", HipadabaTree('\n'.join(lines)).short_tree() root = etree.parse("junk.xml") hipadaba = HipadabaTree(root) print "From tree:", hipadaba.short_tree() print "Components:", [ch.attrib['id'] for ch in hipadaba.root.findall('component')] print "Components:", [ch.attrib['id'] for ch in hipadaba.getNode('/sample/ps9').findall('component')] print "GetNode:", hipadaba.short_tree(hipadaba.getNode('/sample/ps9')) print "PrintTree:" hipadaba.print_tree(tree=hipadaba.getNode('/sample/ps9/')) hipadaba.print_tree(tree=hipadaba.getNode('/sample/ps9/status'), props=True) print "GetChildren:", hipadaba.getChildren('') print "GetChildren:", hipadaba.getChildren('////') print "GetChildren:", hipadaba.getChildren('//sample///ps9/////') print "GetProperties:", hipadaba.getProperties('/sample/ps9') print "Properties from root:" for p in hipadaba.getProperties('/sample/ps9'): prop = hipadaba.getProperty('/sample/ps9', p) print ' ', p, '=', prop n = hipadaba.getNode('/sample/ps9') print "Properties from node:" for p in hipadaba.getProperties('/', n): prop = hipadaba.getProperty('/', p, n) print ' ', p, '=', prop