How to generate XML

Michael Chermside mcherm at destiny.com
Wed Feb 13 14:35:55 EST 2002


>>> I'm amazed that people always start proposing difficult-to-use
>>> libraries when this question comes up. I'd prefer to use
>>>
>>> print "<foo/>"
> 
> For the special case where you have a tree structure whose nodes
> are instances of Python classes, implement an "export" method in
> each class something like the following:

 >
 >    def export(self, outfile, level):
 >             [...]


I tend to agree with the original poster: simply writing your own print 
routines isn't difficult at all. However, if you're going to go around 
putting in standard "export()" methods, perhaps you'd prefer something 
which does it automatically.

The following code will create an xmlPrint() method. Pass it an object, 
and it prints it out in a pseudoreadable fashion. If I were really going 
to be using this, I'd modify _xmlPrintObj() so it checks for a .toXML() 
method and invokes that instead if such a thing exists. But there's no 
reason to write boilerplate in Python, where introspection is so easy.

-- Michael Chermside


------------------------ <code> -------------------------
def xmlPrint(obj, writer=sys.stdout, indentText='   '):
     """Print an object in XML format."""
     _xmlPrintObj(obj, _IndentingWriter(writer, indentText))

class _IndentingWriter:
     def __init__(self,
                  writer=sys.stdout,
                  indentText='   ',
                  indentLevel=0):
         self.writer = writer
         self.indentText = indentText
         self.indentLevel = indentLevel
         self.indentStr = indentText * indentLevel
     def incr(self):
         return IndentingWriter(self.writer, self.indentText,
                                self.indentLevel + 1)
     def writeline(self, text):
         self.writer.write(self.indentStr)
         self.writer.write(text)
         self.writer.write('\n')


def _xmlPrintObj(obj, writer):
     """Print an object in XML format (internal interface)."""
     # Print tags for the object itself based on class name
     tagname = obj.__class__.__name__
     writer.writeline('<%s>' % tagname)

     # for all fields not beginning with an underscore...
     for fieldName in filter(lambda x: x[0]!='_', dir(obj)):
         _xmlPrintField(getattr(obj, fieldName), fieldName,
                        writer.incr())

     # close the tags for the object itself
     writer.writeline('</%s>' % tagname)

def _xmlPrintField(value, fieldName, writer):
     """Print a field of some object, labled with its fieldName."""
     if type(value) == types.InstanceType:
         # for sub-objects we print field name then recurse
         writer.writeline('<%s>' % fieldName)
         _xmlPrintObj(value, writer.incr())
         writer.writeline('</%s>' % fieldName)
     elif type(value) in (types.ListType, types.TupleType):
         # for sequences we print all items
         writer.writeline('<%s>' % fieldName)
         for v in value:
             _xmlPrintField(v, 'value', writer.incr())
         writer.writeline('</%s>' % fieldName)
     else:
         # for all other fields just use str()
         writer.writeline('</%s>%s</%s>' % (fieldName, value, fieldName))
------------------------ </code> -------------------------





More information about the Python-list mailing list