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 = '<?xml version="1.0"?>\n'
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:
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):
"""
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.
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]
+