Handle updating an object.  Based on XML input.

def updateObjectFromXML(xml_doc, obj, mapping):
    """
    Handle updating an object.  Based on XML input.
    """
    nsmap = None
    if isinstance(mapping, dict):
        # The special key @namespaces is used to pass
        # namespaces and prefix mappings for xpath selectors.
        # e.g. {'x': 'http://example.com/namespace'}
        if '@namespaces' in mapping:
            nsmap = mapping['@namespaces']
    else:
        raise TypeError('Tag-to-property map must be a dict.')
    # Iterate over the keys of the translation dictionary from event objects
    # to xml objects, so we can update the fields with the new information
    for k, v in mapping.items():
        if k.startswith('@'):
            continue
        selected_text = None
        if isinstance(v, basestring):
            selector = v
        elif isinstance(v, list):
            selector = '/'.join(v)
        else:
            raise TypeError(
                'Invalid tag-to-property mapping dict: '
                'values must be strings or lists, not %s.' % (type(v),)
            )
        try:
            selected_text = xml_doc.xpath(selector, namespaces=nsmap)
            if isinstance(selected_text, list):
                selected_text = selected_text[0]
            selected_text = selected_text.text
            setattr(obj, k, selected_text)
        except IndexError:
            # Assume the value is missing. It's also possible that the
            # given selector is valid but wrong, but the more common
            # case is that the element is missing. To be consistent with
            # the prior implementation, empty resultsets just mean empty
            # attributes.
            continue
    return obj