From: Tony Mack Date: Thu, 1 Sep 2011 17:19:21 +0000 (-0400) Subject: added XPathFilter, RSpecElement classes. added find(), find_elements(), get_element_a... X-Git-Tag: sfa-1.0-36~46 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=a9af00f5872ace092b39f42f2097cd573fedaf4f;p=sfa.git added XPathFilter, RSpecElement classes. added find(), find_elements(), get_element_attributes() methods --- diff --git a/sfa/rspecs/rspec.py b/sfa/rspecs/rspec.py index f2fa662a..1a0c3ad7 100755 --- a/sfa/rspecs/rspec.py +++ b/sfa/rspecs/rspec.py @@ -4,7 +4,40 @@ from StringIO import StringIO from datetime import datetime, timedelta from sfa.util.xrn import * from sfa.util.plxrn import hostname_to_urn -from sfa.util.faults import SfaNotImplemented, InvalidRSpec +from sfa.util.enumeration import Enum +from sfa.util.faults import SfaNotImplemented, InvalidRSpec, InvalidRSpecElement + + +class XpathFilter: + @staticmethod + def xpath(filter={}): + xpath = "" + if filter: + filter_list = [] + for (key, value) in filter.items(): + if key == 'text': + key = 'text()' + else: + key = '@'+key + if isinstance(value, str): + filter_list.append('%s="%s"' % (key, value)) + elif isinstance(value, list): + filter_list.append('contains("%s", %s)' % (' '.join(map(str, value)), key)) + if filter_list: + xpath = ' and '.join(filter_list) + xpath = '[' + xpath + ']' + return xpath + +# recognized top level rspec elements +RSpecElements = Enum('NETWORK', 'NODE', 'SLIVER', 'INTERFACE', 'LINK', 'VLINK') + +class RSpecElement: + def __init__(self, element_type, name, path): + if not element_type in RSpecElements: + raise InvalidRSpecElement(element_type) + self.type = element_type + self.name = name + self.path = path class RSpec: header = '\n' @@ -14,10 +47,11 @@ class RSpec: version = None namespaces = None user_options = {} - + def __init__(self, rspec="", namespaces={}, type=None, user_options={}): self.type = type self.user_options = user_options + self.elements = {} if rspec: self.parse_rspec(rspec, namespaces) else: @@ -53,8 +87,32 @@ class RSpec: if namespaces: self.namespaces = namespaces + def validate(self, schema): + """ + Validate against rng schema + """ + + relaxng_doc = etree.parse(schema) + relaxng = etree.RelaxNG(relaxng_doc) + if not relaxng(self.xml): + error = relaxng.error_log.last_error + message = "%s (line %s)" % (error.message, error.line) + raise InvalidRSpec(message) + return True + def xpath(self, xpath): - return this.xml.xpath(xpath, namespaces=self.namespaces) + return self.xml.xpath(xpath, namespaces=self.namespaces) + + def register_element_type(self, element_type, element_name, element_path): + if element_type not in RSpecElements: + raise InvalidRSpecElement(element_type, extra="no such element type: %s. Must specify a valid RSpecElement" % element_type) + self.elements[element_type] = RSpecElement(element_type, element_name, element_path) + + def get_element_type(self, element_type): + if element_type not in self.elements: + msg = "ElementType %s not registerd for this rspec" % element_type + raise InvalidRSpecElement(element_type, extra=msg) + return self.elements[element_type] def add_attribute(self, elem, name, value): """ @@ -105,24 +163,43 @@ class RSpec: for element in elements: parent = element.getparent() parent.remove(element) - - def merge(self, in_rspec): - pass + def get_element_attributes(self, elem=None, depth=0): + if elem == None: + elem = self.root_node + attrs = dict(elem.attrib) + attrs['text'] = str(elem.text).strip() + if isinstance(depth, int) and depth > 0: + for child_elem in list(elem): + key = str(child_elem.tag) + if key not in attrs: + attrs[key] = [self.get_element_attributes(child_elem, depth-1)] + else: + attrs[key].append(self.get_element_attributes(child_elem, depth-1)) + else: + attrs['child_nodes'] = list(elem) + return attrs - def validate(self, schema): + def find(self, element_type, filter={}, depth=0): + elements = [self.get_element_attributes(element, depth=depth) for element in \ + self.find_elements(element_type, filter)] + return elements + + def find_elements(self, element_type, filter={}): """ - Validate against rng schema + search for a registered element """ - - relaxng_doc = etree.parse(schema) - relaxng = etree.RelaxNG(relaxng_doc) - if not relaxng(self.xml): - error = relaxng.error_log.last_error - message = "%s (line %s)" % (error.message, error.line) - raise InvalidRSpec(message) - return True - + if element_type not in self.elements: + msg = "Unable to search for element %s in rspec, expath expression not found." % \ + element_type + raise InvalidRSpecElement(element_type, extra=msg) + rspec_element = self.get_element_type(element_type) + xpath = rspec_element.path + XpathFilter.xpath(filter) + return self.xpath(xpath) + + def merge(self, in_rspec): + pass + def cleanup(self): """ Optional method which inheriting classes can choose to implent. @@ -160,5 +237,10 @@ class RSpec: f.close() if __name__ == '__main__': - rspec = RSpec() + rspec = RSpec('/tmp/resources.rspec') print rspec + #rspec.register_element_type(RSpecElements.NETWORK, 'network', '//network') + #rspec.register_element_type(RSpecElements.NODE, 'node', '//node') + #print rspec.find(RSpecElements.NODE)[0] + #print rspec.find(RSpecElements.NODE, depth=1)[0] +