Q:

XML to custom Class

So, I'm retrieving data from one vShield Manager via the API and building a database to syncronize with another...  I'm successfully retreiving XML from the API (yay) and I can parse it just fine, but it's a bit tedious.  I'm trying to create custom classes for the various objects in the vShield (virtual firewalls, global address objects, service definitions, etc.) so I can reference the data in my script in a sane manner, and this is where I'm running into a problem (sort of)...
I get xml back that looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<scopingObjects>
  <object>
    <objectId>datacenter-2</objectId>
    <type>
      <typeName>Datacenter</typeName>
    </type>
    <name>virtualDataCenter-01</name>
    <revision>5</revision>
    <objectTypeName>Datacenter</objectTypeName>
    <scope>
      <id>group-d1</id>
      <objectTypeName>Folder</objectTypeName>
      <name>Datacenters</name>
    </scope>
    <extendedAttributes/>
  </object>
  <object>
    <objectId>globalroot-0</objectId>
    <type>
      <typeName>GlobalRoot</typeName>
    </type>
    <name>Global</name>
    <revision>460</revision>
    <objectTypeName>GlobalRoot</objectTypeName>
    <extendedAttributes/>
  </object>
</scopingObjects>

And I itterate through that using ElementTree:
# Get the list of scoping objects
scopeObjects = [] # Declare an empty list
r = sendRest("getScopes")
xml = et.fromstring( r.text )
for object in xml.iter("object"):
    try:
        o = scope()
        o.create(et.tostring(object))
        scopeObjects.append(o)
    except Exception, e:
        print "Exception: " + repr(e)

Where I use the following class definition:
class scope:
    def __init__(self):
        self.id = ""
        self.name = ""
        self.type = ""
    def create(self, xmlString):
        try:
            xml = et.fromstring(xmlString)
            if xml.find("objectId") is not None: self.id = xml.find("objectId").text
            if xml.find("name") is not None: self.name = xml.find("name").text
            if xml.find("type/typeName") is not None: self.type = xml.find("type/typeName").text
        except:
            print "Error constructing scope object from:\n%s" % xmlString
            return False

Which all works a treat... until I come across the more complicated XML structures... then it's an orgy of "if xml.find("blah/blah/blah") is not None: variable = xml.find("blah/blah/blah").text" over and over again...
I'd like to do something like:
class scope:
  def __init__(self):
    self.id = ""
    self.name = ""
    self.type = ""
  def create(self, xmlString):
    xmlPaths = { "id" : "objectId", "name" : "name", "type" : "type/typeName" }
    for key in xmlPaths.keys():
      element = xml.find(xmlPaths[key])
      if element is not None:
        # Set the class property named by "key" to the value of element.text
        locals()[key] = element.text
        # For example, if the key is "id", then it sets "self.id" to the text of the element in XML tag "<objectId>"

Basically, I want to be lazy when it comes to constructing the objects... I don't want to have to type loads of "if xml....".  It will become much more important when I start dealing with the more complicated objects returned by the API, with scores of elements to deal with.
My basic question: what's the best way to do this?
Cheers!
My Solution:
Many thanks to Larsks for the answer.  Cheers mate!
class scope:
    xmlPathMap = {
        "id" : "objectId",
        "name" : "name",
        "type" : "type/typeName"
    }
    def __init__(self, element):
        self.element = element
        self.create()
    def create(self):
        try:
            for key, path in self.xmlPathMap.items():
                res = self.element.find(path)
                if res is not None:
                    setattr(self, key, res.text)
        except:
            print "Error constructing scope object:\n\tkey: %s\n\tpath: %s\n\tvalue: %s" % (key, path, res.text)
            return False
# End of scope class definition

A:

What about something like this?  This is basically what you're doing in your "I'd like to do something like..." example.  Attributes on scope objects default to None, and then get set using the attribute/xpath dictionary xmlPaths.  There's some stuff going on in your code that I'm not sure about (for example, I'm not sure what you're doing with locals() there), but I think this is doing what you want.
from lxml import etree

class scope(object):
    xmlPaths = {'id': 'objectId',
                'name': 'name',
                'type': 'type/typeName'}

    def __init__(self, element):
        self.id = None
        self.name = None
        self.type = None
        self.element = element

        self.parse()

    def parse(self):
        for attr, path in self.xmlPaths.items():
            res = self.element.xpath(path)
            if res:
                setattr(self, attr, res[0].text)

    def __repr__(self):
        return '<scope id=%s name=%s type=%s>' % (
            self.id, self.name, self.type)

  with open('data.xml') as fd:
      doc = etree.parse(fd)

  scopeObjects = []
  for object in doc.iter('object'):
      o = scope(object)
      scopeObjects.append(o)

  print scopeObjects

