X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Futil%2Fxml.py;h=d6734e630d0484a7ae57144f3415a9c80cc0ef3a;hb=e74265ec6d973c2da8fd470be4331eacc8d09351;hp=e0083fcbccb689b301be61cd4b86e17b6744f105;hpb=ae545a57e0a9701cd7aadbb0d032bbd7c677c8b5;p=sfa.git diff --git a/sfa/util/xml.py b/sfa/util/xml.py index e0083fcb..d6734e63 100755 --- a/sfa/util/xml.py +++ b/sfa/util/xml.py @@ -5,6 +5,7 @@ from StringIO import StringIO from sfa.util.faults import InvalidXML from sfa.rspecs.elements.element import Element +# helper functions to help build xpaths class XpathFilter: @staticmethod @@ -38,21 +39,32 @@ class XpathFilter: xpath = '[' + xpath + ']' return xpath +# a wrapper class around lxml.etree._Element +# the reason why we need this one is because of the limitations +# we've found in xpath to address documents with multiple namespaces defined +# in a nutshell, we deal with xml documents that have +# a default namespace defined (xmlns="http://default.com/") and specific prefixes defined +# (xmlns:foo="http://foo.com") +# according to the documentation instead of writing +# element.xpath ( "//node/foo:subnode" ) +# we'd then need to write xpaths like +# element.xpath ( "//{http://default.com/}node/{http://foo.com}subnode" ) +# which is a real pain.. +# So just so we can keep some reasonable programming style we need to manage the +# namespace map that goes with the _Element (its internal .nsmap being unmutable) + class XmlElement: def __init__(self, element, namespaces): self.element = element - self.tag = element.tag - self.text = element.text - self.attrib = element.attrib self.namespaces = namespaces - + # redefine as few methods as possible def xpath(self, xpath, namespaces=None): if not namespaces: namespaces = self.namespaces elems = self.element.xpath(xpath, namespaces=namespaces) return [XmlElement(elem, namespaces) for elem in elems] - + def add_element(self, tagname, **kwds): element = etree.SubElement(self.element, tagname, **kwds) return XmlElement(element, self.namespaces) @@ -69,7 +81,7 @@ class XmlElement: def get_instance(self, instance_class=None, fields=[]): """ Returns an instance (dict) of this xml element. The instance - holds a reference this xml element. + holds a reference to this xml element. """ if not instance_class: instance_class = Element @@ -121,29 +133,26 @@ class XmlElement: else: self.element.remove(element) - def get(self, key, *args): - return self.element.get(key, *args) - - def items(self): return self.element.items() - - def set(self, key, value): - self.element.set(key, value) - def set_text(self, text): self.element.text = text + # Element does not have unset ?!? def unset(self, key): del self.element.attrib[key] - def iterchildren(self): - return self.element.iterchildren() - def toxml(self): return etree.tostring(self.element, encoding='UTF-8', pretty_print=True) def __str__(self): return self.toxml() + ### other method calls or attribute access like .text or .tag or .get + # are redirected on self.element + def __getattr__ (self, name): + if not hasattr(self.element, name): + raise AttributeError, name + return getattr(self.element, name) + class XML: def __init__(self, xml=None, namespaces=None): @@ -186,11 +195,12 @@ class XML: self.namespaces['default'] = 'default' self.root = XmlElement(root, self.namespaces) - # set schema + # set schema for key in self.root.attrib.keys(): if key.endswith('schemaLocation'): - # schema location should be at the end of the list - schema_parts = self.root.attrib[key].split(' ') + # schemaLocation should be at the end of the list. + # Use list comprehension to filter out empty strings + schema_parts = [x for x in self.root.attrib[key].split(' ') if x] self.schema = schema_parts[1] namespace, schema = schema_parts[0], schema_parts[1] break @@ -199,7 +209,7 @@ class XML: if element is None: if self.root is None: self.parse_xml('<%s/>' % root_tag_name) - element = self.root + element = self.root.element if 'text' in d: text = d.pop('text') @@ -215,9 +225,9 @@ class XML: self.parse_dict(val, key, child_element) elif isinstance(val, basestring): child_element = etree.SubElement(element, key).text = val - + elif isinstance(value, int): - d[key] = unicode(d[key]) + d[key] = unicode(d[key]) elif value is None: d.pop(key) @@ -248,16 +258,14 @@ class XML: namespaces = self.namespaces return self.root.xpath(xpath, namespaces=namespaces) - def set(self, key, value, element=None): - if not element: - element = self.root - return element.set(key, value) + def set(self, key, value): + return self.root.set(key, value) def remove_attribute(self, name, element=None): if not element: element = self.root element.remove_attribute(name) - + def add_element(self, *args, **kwds): """ Wrapper around etree.SubElement(). Adds an element to