#!/usr/bin/python
+from types import StringTypes
from lxml import etree
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, InvalidRSpecElement
+
+from sfa.util.faults import InvalidXML
class XpathFilter:
@staticmethod
try:
tree = etree.parse(StringIO(xml), parser)
except Exception, e:
- raise InvalidRSpec(str(e))
+ raise InvalidXML(str(e))
self.root = tree.getroot()
# set namespaces map
self.namespaces = dict(self.root.nsmap)
- # If the 'None' exist, then it's pointing to the default namespace. This makes
- # it hard for us to write xpath queries for the default naemspace because lxml
- # wont understand a None prefix. We will just associate the default namespeace
- # with a key named 'default'.
- if None in self.namespaces:
- default_namespace = self.namespaces.pop(None)
- self.namespaces['default'] = default_namespace
+ if 'default' not in self.namespaces and None in self.namespaces:
+ # If the 'None' exist, then it's pointing to the default namespace. This makes
+ # it hard for us to write xpath queries for the default naemspace because lxml
+ # wont understand a None prefix. We will just associate the default namespeace
+ # with a key named 'default'.
+ self.namespaces['default'] = self.namespaces[None]
+ else:
+ self.namespaces['default'] = 'default'
# set schema
for key in self.root.attrib.keys():
namespace, schema = schema_parts[0], schema_parts[1]
break
+ def parse_dict(self, d, root_tag_name='xml', element = None):
+ if element is None:
+ if self.root is None:
+ self.parse_xml('<%s/>' % root_tag_name)
+ element = self.root
+
+ if 'text' in d:
+ text = d.pop('text')
+ element.text = text
+
+ # handle repeating fields
+ for (key, value) in d.items():
+ if isinstance(value, list):
+ value = d.pop(key)
+ for val in value:
+ if isinstance(val, dict):
+ child_element = etree.SubElement(element, key)
+ 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])
+ elif value is None:
+ d.pop(key)
+
+ # element.attrib.update will explode if DateTimes are in the
+ # dcitionary.
+ d=d.copy()
+ # looks like iteritems won't stand side-effects
+ for k in d.keys():
+ if not isinstance(d[k],StringTypes):
+ del d[k]
+
+ element.attrib.update(d)
+
def validate(self, schema):
"""
Validate against rng schema
if not relaxng(self.root):
error = relaxng.error_log.last_error
message = "%s (line %s)" % (error.message, error.line)
- raise InvalidRSpec(message)
+ raise InvalidXML(message)
return True
def xpath(self, xpath, namespaces=None):
def add_element(self, name, attrs={}, parent=None, text=""):
"""
- Generic wrapper around etree.SubElement(). Adds an element to
+ Wrapper around etree.SubElement(). Adds an element to
specified parent node. Adds element to root node is parent is
not specified.
"""
return self.toxml()
def toxml(self):
- return etree.tostring(self.root, pretty_print=True)
+ return etree.tostring(self.root, encoding='UTF-8', pretty_print=True)
+
+ # XXX smbaker, for record.load_from_string
+ def todict(self, elem=None):
+ if elem is None:
+ elem = self.root
+ d = {}
+ d.update(elem.attrib)
+ d['text'] = elem.text
+ for child in elem.iterchildren():
+ if child.tag not in d:
+ d[child.tag] = []
+ d[child.tag].append(self.todict(child))
+
+ if len(d)==1 and ("text" in d):
+ d = d["text"]
+
+ return d
def save(self, filename):
f = open(filename, 'w')
f.write(self.toxml())
f.close()
-
-if __name__ == '__main__':
- rspec = RSpec('/tmp/resources.rspec')
- print rspec
+
+# no RSpec in scope
+#if __name__ == '__main__':
+# rspec = RSpec('/tmp/resources.rspec')
+# print rspec