replaced Element.get_elements() with XmlNode.get_instance(). replaced Element.add_ele...
authorTony Mack <tmack@paris.CS.Princeton.EDU>
Thu, 17 Nov 2011 02:56:32 +0000 (21:56 -0500)
committerTony Mack <tmack@paris.CS.Princeton.EDU>
Thu, 17 Nov 2011 02:56:32 +0000 (21:56 -0500)
sfa/rspecs/elements/element.py
sfa/rspecs/elements/versions/pgv2Link.py
sfa/rspecs/elements/versions/pgv2Node.py
sfa/rspecs/elements/versions/pgv2Services.py
sfa/rspecs/elements/versions/pgv2SliverType.py
sfa/rspecs/elements/versions/sfav1Node.py
sfa/rspecs/elements/versions/sfav1Sliver.py
sfa/rspecs/versions/pgv2.py
sfa/rspecs/versions/sfav1.py
sfa/util/xml.py

index 5789a9c..a2febfc 100644 (file)
@@ -11,47 +11,9 @@ class Element(dict):
             if key in fields:
                 self[key] = fields[key] 
 
             if key in fields:
                 self[key] = fields[key] 
 
-    @staticmethod
-    def get_elements(xml, xpath, element_class=None, fields=None):
-        """
-        Search the specifed xml node for elements that match the 
-        specified xpath query. 
-        Returns a list of objects instanced by the specified element_class.
-        """
-        if not element_class:
-            element_class = Element
-        if not fields and hasattr(element_class, 'fields'):
-           fields = element_class.fields
-        elems = xml.xpath(xpath)
-        objs = []
-        for elem in elems:
-            if not fields:
-                obj = element_class(elem.attrib, elem)
-            else:
-                obj = element_class({}, elem)
-                for field in fields:
-                    if field in elem.attrib:
-                        obj[field] = elem.attrib[field]    
-            objs.append(obj)
-        return objs
-
-    @staticmethod
-    def add_elements(xml, name, objs, fields=None):
-        """
-        Adds a child node to the specified xml node based on
-        the specified name , element class and object.    
-        """
-        if not isinstance(objs, list):
-            objs = [objs]
-        elems = []
-        for obj in objs:
-            if not obj:
-                continue
-            if not fields:
-                fields = obj.keys()
-            elem = xml.add_element(name)
-            for field in fields:
-                if field in obj and obj[field]:
-                    elem.set(field, unicode(obj[field]))
-            elems.append(elem)
-        return elems
+    def __getattr__(self, attr):
+        if hasattr(self, attr):
+            return getattr(self, attr)
+        elif self.element is not None and hasattr(self.element, attr):
+            return getattr(self.element, attr)
+        raise AttributeError, "Element class has no attribute %s" % attr
index e496d16..65513d0 100644 (file)
@@ -9,14 +9,14 @@ class PGv2Link:
     @staticmethod
     def add_links(xml, links):
         for link in links:
     @staticmethod
     def add_links(xml, links):
         for link in links:
-            link_elems = Element.add(xml, 'link', link, ['component_name', 'component_id', 'client_id'])
-            link_elem = link_elems[0]
+            
+            link_elem = xml.add_instance('link', link, ['component_name', 'component_id', 'client_id'])
             # set component manager element            
             if 'component_manager' in link and link['component_manager']:
                 cm_element = link_elem.add_element('component_manager', name=link['component_manager'])
             # set interface_ref elements
             for if_ref in [link['interface1'], link['interface2']]:
             # set component manager element            
             if 'component_manager' in link and link['component_manager']:
                 cm_element = link_elem.add_element('component_manager', name=link['component_manager'])
             # set interface_ref elements
             for if_ref in [link['interface1'], link['interface2']]:
-                Element.add(link_elem, 'interface_ref', if_ref, Interface.fields)
+                link_elem.add_instance('interface_ref', if_ref, Interface.fields)
             # set property elements
             prop1 = link_elem.add_element('property', source_id = link['interface1']['component_id'],
                 dest_id = link['interface2']['component_id'], capacity=link['capacity'], 
             # set property elements
             prop1 = link_elem.add_element('property', source_id = link['interface1']['component_id'],
                 dest_id = link['interface2']['component_id'], capacity=link['capacity'], 
@@ -55,7 +55,8 @@ class PGv2Link:
                         link[attrib] = prop[attrib]
                              
             # get interfaces
                         link[attrib] = prop[attrib]
                              
             # get interfaces
-            interfaces = Element.get(Interface, link_elem, './default:interface_ref | ./interface_ref')
+            iface_elems = link_elem.xpath('./default:interface_ref | ./interface_ref')
+            interfaces = [iface_elem.get_instance(Interface) for iface_elem in iface_elems]
             if len(interfaces) > 1:
                 link['interface1'] = interfaces[0]
                 link['interface2'] = interfaces[1] 
             if len(interfaces) > 1:
                 link['interface1'] = interfaces[0]
                 link['interface2'] = interfaces[1] 
index 4836cab..eb0518f 100644 (file)
@@ -1,7 +1,6 @@
 from sfa.util.plxrn import PlXrn, xrn_to_hostname
 from sfa.util.xrn import Xrn
 from sfa.util.xml import XpathFilter
 from sfa.util.plxrn import PlXrn, xrn_to_hostname
 from sfa.util.xrn import Xrn
 from sfa.util.xml import XpathFilter
-from sfa.rspecs.elements.element import Element
 from sfa.rspecs.elements.node import Node
 from sfa.rspecs.elements.sliver import Sliver
 from sfa.rspecs.elements.location import Location
 from sfa.rspecs.elements.node import Node
 from sfa.rspecs.elements.sliver import Sliver
 from sfa.rspecs.elements.location import Location
@@ -19,19 +18,21 @@ class PGv2Node:
         node_elems = []
         for node in nodes:
             node_fields = ['component_manager_id', 'component_id', 'client_id', 'sliver_id', 'exclusive']
         node_elems = []
         for node in nodes:
             node_fields = ['component_manager_id', 'component_id', 'client_id', 'sliver_id', 'exclusive']
-            elems = Element.add_elements(xml, 'node', node, node_fields)
-            node_elem = elems[0]
+            node_elem = xml.add_instance('node', node, node_fields)
             node_elems.append(node_elem)
             # set component name
             if node.get('component_id'):
                 component_name = xrn_to_hostname(node['component_id'])
                 node_elem.set('component_name', component_name)
             node_elems.append(node_elem)
             # set component name
             if node.get('component_id'):
                 component_name = xrn_to_hostname(node['component_id'])
                 node_elem.set('component_name', component_name)
-            # set hardware types 
-            Element.add_elements(node_elem, 'hardware_type', node.get('hardware_types', []), HardwareType.fields) 
-            # set location       
-            location_elems = Element.add_elements(node_elem, 'location', node.get('location', []), Location.fields)
+            # set hardware types
+            for hardware_type in node.get('hardware_types', []): 
+                node_elem.add_instance('hardware_type', hardware_type, HardwareType.fields)
+            # set location
+            if node.get('location'):
+                node_elem.add_instance('location', node['location'], Location.fields)       
             # set interfaces
             # set interfaces
-            interface_elems = Element.add_elements(node_elem, 'interface', node.get('interfaces', []), ['component_id', 'client_id', 'ipv4'])
+            for interface in  node.get('interfaces', []):
+                node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4'])
             # set available element
             if node.get('boot_state', '').lower() == 'boot':
                 available_elem = node_elem.add_element('available', now='True')
             # set available element
             if node.get('boot_state', '').lower() == 'boot':
                 available_elem = node_elem.add_element('available', now='True')
@@ -72,17 +73,29 @@ class PGv2Node:
             nodes.append(node) 
             if 'component_id' in node_elem.attrib:
                 node['authority_id'] = Xrn(node_elem.attrib['component_id']).get_authority_urn()
             nodes.append(node) 
             if 'component_id' in node_elem.attrib:
                 node['authority_id'] = Xrn(node_elem.attrib['component_id']).get_authority_urn()
+            
+            # get hardware types
+            hardware_type_elems = node_elem.xpath('./default:hardwate_type | ./hardware_type')
+            node['hardware_types'] = [hw_type.get_instnace(HardwareType) for hw_type in hardware_type_elems]
+            
+            # get location
+            location_elems = node_elem.xpath('./default:location | ./location')
+            locations = [location_elem.get_instance(Location) for location_elem in location_elems]
+            if len(locations) > 0:
+                node['location'] = locations[0]
 
 
-            node['hardware_types'] = Element.get_elements(node_elem, './default:hardwate_type | ./hardware_type', HardwareType)
-            location_elems = Element.get_elements(node_elem, './default:location | ./location', Location)
-            if len(location_elems) > 0:
-                node['location'] = location_elems[0]
-            node['interfaces'] = Element.get_elements(node_elem, './default:interface | ./interface', Interface)
+            # get interfaces
+            iface_elems = node_elem.xpath('./default:interface | ./interface')
+            node['interfaces'] = [iface_elem.get_instance(Interface) for iface_elem in iface_elems]
+
+            # get services
             node['services'] = PGv2Services.get_services(node_elem)
             node['services'] = PGv2Services.get_services(node_elem)
+            
+            # get slivers
             node['slivers'] = PGv2SliverType.get_slivers(node_elem)    
             node['slivers'] = PGv2SliverType.get_slivers(node_elem)    
-            available_elem = Element.get_elements(node_elem, './default:available | ./available', fields=['now'])
-            if len(available_elem) > 0 and 'name' in available_elem[0]:
-                if available_elem[0].get('now', '').lower() == 'true': 
+            available_elems = node_elem.xpath('./default:available | ./available')
+            if len(available_elems) > 0 and 'name' in available_elems[0].attrib:
+                if available_elems[0].attrib.get('now', '').lower() == 'true': 
                     node['boot_state'] = 'boot'
                 else: 
                     node['boot_state'] = 'disabled' 
                     node['boot_state'] = 'boot'
                 else: 
                     node['boot_state'] = 'disabled' 
index 9eb1ed9..9fadc56 100644 (file)
@@ -8,21 +8,35 @@ class PGv2Services:
     def add_services(xml, services):
         if not services:
             return 
     def add_services(xml, services):
         if not services:
             return 
-
         for service in services:
             service_elem = xml.add_element('services')
         for service in services:
             service_elem = xml.add_element('services')
-            Element.add_elements(service_elem, 'install', service.get('install', []), Install.fields) 
-            Element.add_elements(service_elem, 'execute', service.get('execute', []), Execute.fields) 
-            Element.add_elements(service_elem, 'login', service.get('login', []), Login.fields) 
+            child_elements = {'install': Install.fields,
+                              'execute': Execute.fields,
+                              'login': Login.fields}
+            for (name, fields) in child_elements.items():
+                objects = service.get(name)
+                if not objects: 
+                    continue
+                if isinstance(objects, basestring):
+                    service_elem.add_instance(name, objects, fields)
+                elif isinstance(objects, list):
+                    for obj in objects:
+                        service_elem.add_instance(name, obj, fields)
               
     @staticmethod
     def get_services(xml):
         services = []
         for services_elem in xml.xpath('./default:services | ./services'):
             service = Services(services_elem.attrib, services_elem)
               
     @staticmethod
     def get_services(xml):
         services = []
         for services_elem in xml.xpath('./default:services | ./services'):
             service = Services(services_elem.attrib, services_elem)
-            service['install'] = Element.get_elements(service_elem, './default:install | ./install', Install)
-            service['execute'] = Element.get_elements(service_elem, './default:execute | ./execute', Execute)
-            service['login'] = Element.get_elements(service_elem, './default:login | ./login', Login)
+            # get install 
+            install_elems = xml.xpath('./default:install | ./install')
+            service['install'] = [install_elem.get_instance(Install) for install_elem in install_elems]
+            # get execute
+            execute_elems = xml.xpath('./default:execute | ./execute')
+            service['execute'] = [execute_elem.get_instance(Execute) for execute_elem in execute_elems]
+            # get login
+            login_elems = xml.xpath('./default:login | ./login')
+            service['login'] = [login_elem.get_instance(Login) for login_elem in login_elems]
             services.append(service)  
         return services
 
             services.append(service)  
         return services
 
index c071532..4271d21 100644 (file)
@@ -10,7 +10,7 @@ class PGv2SliverType:
         if not isinstance(slivers, list):
             slivers = [slivers]
         for sliver in slivers: 
         if not isinstance(slivers, list):
             slivers = [slivers]
         for sliver in slivers: 
-            sliver_elem = Element.add_elements(xml, 'sliver_type', sliver, ['type', 'client_id'])
+            sliver_elem = xml.add_instance('sliver_type', sliver, ['type', 'client_id'])
             PGv2SliverType.add_sliver_attributes(sliver_elem, sliver.get('pl_tags', []))
     
     @staticmethod
             PGv2SliverType.add_sliver_attributes(sliver_elem, sliver.get('pl_tags', []))
     
     @staticmethod
index 9933ece..61f8056 100644 (file)
@@ -19,19 +19,19 @@ class SFAv1Node:
 
     @staticmethod
     def add_nodes(xml, nodes):
 
     @staticmethod
     def add_nodes(xml, nodes):
-        network_elems = Element.get_elements(xml, '//network', fields=['name'])
+        network_elems = xml.xpath('//network')
         if len(network_elems) > 0:
             network_elem = network_elems[0]
         elif len(nodes) > 0 and nodes[0].get('component_manager_id'):
         if len(network_elems) > 0:
             network_elem = network_elems[0]
         elif len(nodes) > 0 and nodes[0].get('component_manager_id'):
-            network_urn = nodes[0]['component_manager_id']    
-            network_elems = Element.add_elements(xml, 'network', {'name': Xrn(network_urn).get_hrn()})
-            network_elem = network_elems[0]
+            network_urn = nodes[0]['component_manager_id']
+            network_elem = xml.add_element('network', name = Xrn(network_urn).get_hrn()[0])     
+        else:
+            network_elem = xml
 
         node_elems = []       
         for node in nodes:
             node_fields = ['component_manager_id', 'component_id', 'boot_state']
 
         node_elems = []       
         for node in nodes:
             node_fields = ['component_manager_id', 'component_id', 'boot_state']
-            elems = Element.add_elements(network_elem, 'node', node, node_fields)
-            node_elem = elems[0]  
+            node_elem = network_elem.add_instance('node', node, node_fields)
             node_elems.append(node_elem)
 
             # determine network hrn
             node_elems.append(node_elem)
 
             # determine network hrn
@@ -43,17 +43,20 @@ class SFAv1Node:
             if 'component_id' in node and node['component_id']:
                 component_name = xrn_to_hostname(node['component_id'])
                 node_elem.set('component_name', component_name)
             if 'component_id' in node and node['component_id']:
                 component_name = xrn_to_hostname(node['component_id'])
                 node_elem.set('component_name', component_name)
-                hostname_tag = node_elem.add_element('hostname')
-                hostname_tag.set_text(component_name)
+                hostname_elem = node_elem.add_element('hostname')
+                hostname_elem.set_text(component_name)
 
             # set site id
             if 'authority_id' in node and node['authority_id']:
                 node_elem.set('site_id', node['authority_id'])
 
 
             # set site id
             if 'authority_id' in node and node['authority_id']:
                 node_elem.set('site_id', node['authority_id'])
 
-            location_elems = Element.add_elements(node_elem, 'location',
-                                                  node.get('location', []), Location.fields)
-            interface_elems = Element.add_elements(node_elem, 'interface', 
-                                                   node.get('interfaces', []), ['component_id', 'client_id', 'ipv4'])
+            # add locaiton
+            location = node.get('location')
+            if location:
+                node_elem.add_instance('location', location, Location.fields)
+
+            for interface in node.get('interfaces', []):
+                node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4']) 
             
             #if 'bw_unallocated' in node and node['bw_unallocated']:
             #    bw_unallocated = etree.SubElement(node_elem, 'bw_unallocated', units='kbps').text = str(int(node['bw_unallocated'])/1000)
             
             #if 'bw_unallocated' in node and node['bw_unallocated']:
             #    bw_unallocated = etree.SubElement(node_elem, 'bw_unallocated', units='kbps').text = str(int(node['bw_unallocated'])/1000)
@@ -95,21 +98,6 @@ class SFAv1Node:
         node_elems = xml.xpath(xpath)
         return SFAv1Node.get_node_objs(node_elems)
 
         node_elems = xml.xpath(xpath)
         return SFAv1Node.get_node_objs(node_elems)
 
-    # xxx Thierry : an ugly hack to get the tests to pass again
-    # probably this needs to be trashed
-    # the original code returned the <sliver /> tag, 
-    # but we prefer the <node> father node instead as it already holds data
-    # initially this was to preserve the nodename...
-    # xxx I don't get the ' | //default:node/default:sliver' ...
-    @staticmethod
-    def get_nodes_with_slivers_thierry(xml):
-        # dropping the ''
-        xpath = '//node[count (sliver)>0]'
-        node_elems = xml.xpath(xpath)
-        #  we need to check/recompute the node data 
-        
-        return node_elems
-
     @staticmethod
     def get_nodes_with_slivers(xml):
         xpath = '//node[count(sliver)>0] | //default:node[count(default:sliver)>0]' 
     @staticmethod
     def get_nodes_with_slivers(xml):
         xpath = '//node[count(sliver)>0] | //default:node[count(default:sliver)>0]' 
@@ -124,16 +112,25 @@ class SFAv1Node:
             node = Node(node_elem.attrib, node_elem)
             if 'site_id' in node_elem.attrib:
                 node['authority_id'] = node_elem.attrib['site_id']
             node = Node(node_elem.attrib, node_elem)
             if 'site_id' in node_elem.attrib:
                 node['authority_id'] = node_elem.attrib['site_id']
-            location_objs = Element.get_elements(node_elem, './default:location | ./location', Location)
-            if len(location_objs) > 0:
-                node['location'] = location_objs[0]
-            bwlimit_objs = Element.get_elements(node_elem, './default:bw_limit | ./bw_limit', BWlimit)
-            if len(bwlimit_objs) > 0:
-                node['bwlimit'] = bwlimit_objs[0]
-            node['interfaces'] = Element.get_elements(node_elem, './default:interface | ./interface', Interface)
+            # get location
+            location_elems = node_elem.xpath('./default:location | ./location')
+            locations = [loc_elem.get_instance(Location) for loc_elem in location_elems]  
+            if len(locations) > 0:
+                node['location'] = locations[0]
+            # get bwlimit
+            bwlimit_elems = node_elem.xpath('./default:bw_limit | ./bw_limit')
+            bwlimits = [bwlimit_elem.get_instance(BWlimit) for bwlimit_elem in bwlimit_elems]
+            if len(bwlimits) > 0:
+                node['bwlimit'] = bwlimits[0]
+            # get interfaces
+            iface_elems = node_elem.xpath('./default:interface | ./interface')
+            ifaces = [iface_elem.get_instance(Interface) for iface_elem in iface_elems]
+            node['interfaces'] = ifaces
+            # get services
             node['services'] = PGv2Services.get_services(node_elem) 
             node['services'] = PGv2Services.get_services(node_elem) 
+            # get slivers
             node['slivers'] = SFAv1Sliver.get_slivers(node_elem)
             node['slivers'] = SFAv1Sliver.get_slivers(node_elem)
-#thierry    node['tags'] =  SFAv1PLTag.get_pl_tags(node_elem, ignore=Node.fields.keys())
+            # get tags
             node['tags'] =  SFAv1PLTag.get_pl_tags(node_elem, ignore=Node.fields)
             nodes.append(node)
         return nodes            
             node['tags'] =  SFAv1PLTag.get_pl_tags(node_elem, ignore=Node.fields)
             nodes.append(node)
         return nodes            
index d0a7592..e8fc0b7 100644 (file)
@@ -12,7 +12,7 @@ class SFAv1Sliver:
         if not isinstance(slivers, list):
             slivers = [slivers]
         for sliver in slivers:
         if not isinstance(slivers, list):
             slivers = [slivers]
         for sliver in slivers:
-            sliver_elem = Element.add_elements(xml, 'sliver', sliver, ['name'])[0]
+            sliver_elem = xml.add_instance('sliver', sliver, ['name'])
             SFAv1Sliver.add_sliver_attributes(sliver_elem, sliver.get('tags', []))
             if sliver.get('sliver_id'):
                 sliver_id_leaf = Xrn(sliver.get('sliver_id')).get_leaf()
             SFAv1Sliver.add_sliver_attributes(sliver_elem, sliver.get('tags', []))
             if sliver.get('sliver_id'):
                 sliver_id_leaf = Xrn(sliver.get('sliver_id')).get_leaf()
index ceff971..60387dc 100644 (file)
@@ -1,6 +1,6 @@
 from copy import deepcopy
 from StringIO import StringIO
 from copy import deepcopy
 from StringIO import StringIO
-from sfa.util.xrn import urn_to_sliver_id
+from sfa.util.xrn import Xrn, urn_to_sliver_id
 from sfa.util.plxrn import hostname_to_urn, xrn_to_hostname 
 from sfa.rspecs.baseversion import BaseVersion
 from sfa.rspecs.elements.versions.pgv2Link import PGv2Link
 from sfa.util.plxrn import hostname_to_urn, xrn_to_hostname 
 from sfa.rspecs.baseversion import BaseVersion
 from sfa.rspecs.elements.versions.pgv2Link import PGv2Link
@@ -20,18 +20,16 @@ class PGv2(BaseVersion):
     namespaces = dict(extensions.items() + [('default', namespace)])
 
     # Networks    
     namespaces = dict(extensions.items() + [('default', namespace)])
 
     # Networks    
-    def get_network(self):
-        network = None
-        nodes = self.xml.xpath('//default:node[@component_manager_id][1]', namespaces=self.namespaces)
-        if nodes:
-            network  = nodes[0].get('component_manager_id')
-        return network
-
     def get_networks(self):
     def get_networks(self):
-        networks = self.xml.xpath('//default:node[@component_manager_id]/@component_manager_id', namespaces=self.namespaces)
-        return set(networks)
+        networks = set()
+        nodes = self.xml.xpath('//default:node[@component_manager_id]', namespaces=self.namespaces)
+        for node in nodes: 
+            if 'component_manager_id' in node:
+                network_urn  = node.get('component_manager_id')
+                network_hrn = Xrn(network_urn).get_hrn()[0]
+                networks.add({'name': network_hrn})
+        return list(networks)
 
 
-    
     # Nodes
 
     def get_nodes(self, filter=None):
     # Nodes
 
     def get_nodes(self, filter=None):
index 85aa86e..39a5348 100644 (file)
@@ -23,12 +23,16 @@ class SFAv1(BaseVersion):
 
     # Network 
     def get_networks(self):
 
     # Network 
     def get_networks(self):
-        return Element.get_elements(self.xml, '//network', Element)
+        network_elems = self.xml.xpath('//network')
+        networks = [network_elem.get_instance(fields=['name', 'slice']) for \
+                    network_elem in network_elems]
+        return networks    
+
 
     def add_network(self, network):
         network_tags = self.xml.xpath('//network[@name="%s"]' % network)
         if not network_tags:
 
     def add_network(self, network):
         network_tags = self.xml.xpath('//network[@name="%s"]' % network)
         if not network_tags:
-            network_tag = etree.SubElement(self.xml.root, 'network', name=network)
+            network_tag = self.xml.add_element('network', name=network)
         else:
             network_tag = network_tags[0]
         return network_tag
         else:
             network_tag = network_tags[0]
         return network_tag
index bb298a3..d6fd196 100755 (executable)
@@ -3,6 +3,7 @@ from types import StringTypes
 from lxml import etree
 from StringIO import StringIO
 from sfa.util.faults import InvalidXML
 from lxml import etree
 from StringIO import StringIO
 from sfa.util.faults import InvalidXML
+from sfa.rspecs.elements.element import Element
 
 class XpathFilter:
     @staticmethod
 
 class XpathFilter:
     @staticmethod
@@ -37,32 +38,64 @@ class XpathFilter:
                 xpath = '[' + xpath + ']'
         return xpath
 
                 xpath = '[' + xpath + ']'
         return xpath
 
-class XmlNode:
-    def __init__(self, node, namespaces):
-        self.node = node
-        self.text = node.text
+class XmlElement:
+    def __init__(self, element, namespaces):
+        self.element = element
+        self.text = element.text
         self.namespaces = namespaces
         self.namespaces = namespaces
-        self.attrib = node.attrib
+        self.attrib = element.attrib
         
 
     def xpath(self, xpath, namespaces=None):
         if not namespaces:
             namespaces = self.namespaces 
         
 
     def xpath(self, xpath, namespaces=None):
         if not namespaces:
             namespaces = self.namespaces 
-        elems = self.node.xpath(xpath, namespaces=namespaces)
-        return [XmlNode(elem, namespaces) for elem in elems]
+        elems = self.element.xpath(xpath, namespaces=namespaces)
+        return [XmlElement(elem, namespaces) for elem in elems]
     
     def add_element(self, tagname, **kwds):
     
     def add_element(self, tagname, **kwds):
-        element = etree.SubElement(self.node, tagname, **kwds)
-        return XmlNode(element, self.namespaces)
+        element = etree.SubElement(self.element, tagname, **kwds)
+        return XmlElement(element, self.namespaces)
 
     def append(self, elem):
 
     def append(self, elem):
-        if isinstance(elem, XmlNode):
-            self.node.append(elem.node)
+        if isinstance(elem, XmlElement):
+            self.element.append(elem.element)
         else:
         else:
-            self.node.append(elem)
+            self.element.append(elem)
 
     def getparent(self):
 
     def getparent(self):
-        return XmlNode(self.node.getparent(), self.namespaces)
+        return XmlElement(self.element.getparent(), self.namespaces)
+
+    def get_instance(self, instance_class=None, fields=[]):
+        """
+        Returns an instance (dict) of this xml element. The instance
+        holds a reference this xml element.   
+        """
+        if not instance_class:
+            instance_class = Element
+        if not fields and hasattr(instance_class, 'fields'):
+            fields = instance_class.fields
+
+        if not fields:
+            instance = instance_class(self.attrib, self)
+        else:
+            instance = instance_class({}, self)
+            for field in fields:
+                if field in self.attrib:
+                   instance[field] = self.attrib[field]  
+        return instance             
+
+    def add_instance(self, name, instance, fields=[]):
+        """
+        Adds the specifed instance(s) as a child element of this xml 
+        element. 
+        """
+        if not fields and hasattr(instance, 'keys'):
+            fields = instance.keys()
+        elem = self.add_element(name)
+        for field in fields:
+            if field in instance and instance[field]:
+                elem.set(field, unicode(instance[field]))
+        return elem                  
 
     def remove_elements(self, name):
         """
 
     def remove_elements(self, name):
         """
@@ -72,36 +105,36 @@ class XmlNode:
         
         if not element_name.startswith('//'):
             element_name = '//' + element_name
         
         if not element_name.startswith('//'):
             element_name = '//' + element_name
-        elements = self.node.xpath('%s ' % name, namespaces=self.namespaces) 
+        elements = self.element.xpath('%s ' % name, namespaces=self.namespaces) 
         for element in elements:
             parent = element.getparent()
             parent.remove(element)
 
     def remove(self, element):
         for element in elements:
             parent = element.getparent()
             parent.remove(element)
 
     def remove(self, element):
-        if isinstance(element, XmlNode):
-            self.node.remove(element.node)
+        if isinstance(element, XmlElement):
+            self.element.remove(element.element)
         else:
         else:
-            self.node.remove(element)
+            self.element.remove(element)
 
     def get(self, key, *args):
 
     def get(self, key, *args):
-        return self.node.get(key, *args)
+        return self.element.get(key, *args)
 
 
-    def items(self): return self.node.items()
+    def items(self): return self.element.items()
 
     def set(self, key, value):
 
     def set(self, key, value):
-        self.node.set(key, value)
+        self.element.set(key, value)
     
     def set_text(self, text):
     
     def set_text(self, text):
-        self.node.text = text
+        self.element.text = text
     
     def unset(self, key):
     
     def unset(self, key):
-        del self.node.attrib[key]
+        del self.element.attrib[key]
   
     def iterchildren(self):
   
     def iterchildren(self):
-        return self.node.iterchildren()
+        return self.element.iterchildren()
      
     def toxml(self):
      
     def toxml(self):
-        return etree.tostring(self.node, encoding='UTF-8', pretty_print=True)                    
+        return etree.tostring(self.element, encoding='UTF-8', pretty_print=True)                    
 
     def __str__(self):
         return self.toxml()
 
     def __str__(self):
         return self.toxml()
@@ -115,7 +148,7 @@ class XML:
         self.schema = None
         if isinstance(xml, basestring):
             self.parse_xml(xml)
         self.schema = None
         if isinstance(xml, basestring):
             self.parse_xml(xml)
-        if isinstance(xml, XmlNode):
+        if isinstance(xml, XmlElement):
             self.root = xml
             self.namespaces = xml.namespaces
         elif isinstance(xml, etree._ElementTree) or isinstance(xml, etree._Element):
             self.root = xml
             self.namespaces = xml.namespaces
         elif isinstance(xml, etree._ElementTree) or isinstance(xml, etree._Element):
@@ -147,7 +180,7 @@ class XML:
         else:
             self.namespaces['default'] = 'default' 
 
         else:
             self.namespaces['default'] = 'default' 
 
-        self.root = XmlNode(root, self.namespaces)
+        self.root = XmlElement(root, self.namespaces)
         # set schema 
         for key in self.root.attrib.keys():
             if key.endswith('schemaLocation'):
         # set schema 
         for key in self.root.attrib.keys():
             if key.endswith('schemaLocation'):
@@ -210,48 +243,43 @@ class XML:
             namespaces = self.namespaces
         return self.root.xpath(xpath, namespaces=namespaces)
 
             namespaces = self.namespaces
         return self.root.xpath(xpath, namespaces=namespaces)
 
-    def set(self, key, value, node=None):
-        if not node:
-            node = self.root 
-        return node.set(key, value)
+    def set(self, key, value, element=None):
+        if not element:
+            element = self.root 
+        return element.set(key, value)
 
 
-    def remove_attribute(self, name, node=None):
-        if not node:
-            node = self.root
-        node.remove_attribute(name) 
+    def remove_attribute(self, name, element=None):
+        if not element:
+            element = self.root
+        element.remove_attribute(name) 
         
         
-    def add_element(self, name, **kwds):
+    def add_element(self, *args, **kwds):
         """
         Wrapper around etree.SubElement(). Adds an element to 
         specified parent node. Adds element to root node is parent is 
         not specified. 
         """
         """
         Wrapper around etree.SubElement(). Adds an element to 
         specified parent node. Adds element to root node is parent is 
         not specified. 
         """
-        parent = self.root
-        xmlnode = parent.add_element(name, *kwds)
-        return xmlnode
+        return self.root.add_element(*args, **kwds)
 
 
-    def remove_elements(self, name, node = None):
+    def remove_elements(self, name, element = None):
         """
         Removes all occurences of an element from the tree. Start at 
         specified root_node if specified, otherwise start at tree's root.   
         """
         """
         Removes all occurences of an element from the tree. Start at 
         specified root_node if specified, otherwise start at tree's root.   
         """
-        if not node:
-            node = self.root
+        if not element:
+            element = self.root
+
+        element.remove_elements(name)
 
 
-        node.remove_elements(name)
+    def add_instance(self, *args, **kwds):
+        return self.root.add_instance(*args, **kwds)
 
 
-    def attributes_list(self, elem):
-        # convert a list of attribute tags into list of tuples
-        # (tagnme, text_value)
-        opts = []
-        if elem is not None:
-            for e in elem:
-                opts.append((e.tag, str(e.text).strip()))
-        return opts
+    def get_instance(self, *args, **kwds):
+        return self.root.get_instnace(*args, **kwds)
 
     def get_element_attributes(self, elem=None, depth=0):
         if elem == None:
 
     def get_element_attributes(self, elem=None, depth=0):
         if elem == None:
-            elem = self.root_node
+            elem = self.root
         if not hasattr(elem, 'attrib'):
             # this is probably not an element node with attribute. could be just and an
             # attribute, return it
         if not hasattr(elem, 'attrib'):
             # this is probably not an element node with attribute. could be just and an
             # attribute, return it
@@ -283,7 +311,7 @@ class XML:
         return self.toxml()
 
     def toxml(self):
         return self.toxml()
 
     def toxml(self):
-        return etree.tostring(self.root.node, encoding='UTF-8', pretty_print=True)  
+        return etree.tostring(self.root.element, encoding='UTF-8', pretty_print=True)  
     
     # XXX smbaker, for record.load_from_string
     def todict(self, elem=None):
     
     # XXX smbaker, for record.load_from_string
     def todict(self, elem=None):