X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Futil%2Fxml.py;h=ba324c7b366655cf14504835522ab9e68e1ea100;hb=acd13fb68264ecdc1996954f3f464537806f7380;hp=e0083fcbccb689b301be61cd4b86e17b6744f105;hpb=ae545a57e0a9701cd7aadbb0d032bbd7c677c8b5;p=sfa.git diff --git a/sfa/util/xml.py b/sfa/util/xml.py index e0083fcb..ba324c7b 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 @@ -19,7 +20,8 @@ class XpathFilter: return xpath @staticmethod - def xpath(filter={}): + def xpath(filter=None): + if filter is None: filter={} xpath = "" if filter: filter_list = [] @@ -38,21 +40,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) @@ -66,11 +79,12 @@ class XmlElement: def getparent(self): return XmlElement(self.element.getparent(), self.namespaces) - def get_instance(self, instance_class=None, fields=[]): + def get_instance(self, instance_class=None, fields=None): """ Returns an instance (dict) of this xml element. The instance - holds a reference this xml element. + holds a reference to this xml element. """ + if fields is None: fields=[] if not instance_class: instance_class = Element if not fields and hasattr(instance_class, 'fields'): @@ -85,11 +99,12 @@ class XmlElement: instance[field] = self.attrib[field] return instance - def add_instance(self, name, instance, fields=[]): + def add_instance(self, name, instance, fields=None): """ Adds the specifed instance(s) as a child element of this xml element. """ + if fields is None: fields=[] if not fields and hasattr(instance, 'keys'): fields = instance.keys() elem = self.add_element(name) @@ -121,29 +136,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 +198,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 +212,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 +228,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 +261,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