ActiveState Code

Recipe 440595: Extensible object to XML convertor


This function generates XML for any Python object through recursive functions. It is easy to add specific handlers for your own object types for more complex output options.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def getXML(obj, objname=None):
    """getXML(obj, objname=None)
    returns an object as XML where Python object names are the tags.
    
    >>> u={'UserID':10,'Name':'Mark','Group':['Admin','Webmaster']}
    >>> getXML(u,'User')
    '<User><UserID>10</UserID><Name>Mark</Name><Group>Admin</Group><Group>Webmaster</Group></User>'
    """
    if obj == None:
        return ""
    if not objname:
        objname = "Deepdesk"
    adapt={
        dict: getXML_dict,
        list: getXML_list,
        tuple: getXML_list,
        }
    if adapt.has_key(obj.__class__):
        return adapt[obj.__class__](obj, objname)
    else:
        return "<%(n)s>%(o)s</%(n)s>"%{'n':objname,'o':str(obj)}

def getXML_dict(indict, objname=None):
    h = "<%s>"%objname
    for k, v in indict.items():
        h += getXML(v, k)
    h += "</%s>"%objname
    return h

def getXML_list(inlist, objname=None):
    h = ""
    for i in inlist:
        h += getXML(i, objname)
    return h

Discussion

To support your own object types just create a getXML_myobj function and add the object type and function to adapt.

The function should take two arguments. First is the object to be converted and the second is the objname which should default to None.

The function should return a string with the XML for that object. getXML (or equivalent) should be called for any sub-objects as per the getXML_dict and getXML_list code.

This is a cut down version (my custom object handlers removed) of code I am using for a forthcoming project called Deepdesk.

Comments

  1. 1. At 12:20 p.m. on 28 sep 2005, Jonathan Kolyer said:

    Some Tweaks. I added some tweaks for formatting, CDATA, and compactness:

    def toXML(obj,objname,nodePrefix='', isCdata=False):
        if obj == None:
            return ""
        if adapt.has_key(obj.__class__):
            return adapt[obj.__class__](objname,obj)
        else:
            objXML = None
            if hasattr(obj, 'toXML'):
                objXML = obj.toXML(nodePrefix)
                if not objXML: return ''
            if not objXML: objXML = str(obj)
            if objXML and len(objXML)>0:
                if isCdata:
                    return "%s&lt;%s&gt;&lt;![CDATA[%s]]&gt;&lt;/%s&gt;\n"%(nodePrefix,objname,objXML,objname)
                else:
                    return "%s&lt;%s&gt;%s&lt;/%s&gt;\n"%(nodePrefix,objname,objXML,objname)
            else: return "%s&lt;%s/&gt;\n"%(nodePrefix,objname)
    

Sign in to comment