How to generate XML

Mark McEahern marklists at mceahern.com
Wed Feb 13 15:50:12 EST 2002


[Michael Chermside]
> 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.

There seem to be two bugs in the code you posted, Michael.  For what it's
worth, here's a fully working demo of the code with the minor bug fixes:

#! /usr/bin/env python
# xmlPrint.py
#
# Code from Michael Chermside's posting to comp.lang.python
#
# http://mail.python.org/pipermail/python-list/2002-February/087283.html

import sys
import types

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))

if __name__=="__main__":
    class Person:pass
    p = Person()
    p.firstName = "Mark"
    p.lastName = "McEahern"
    p.favoriteColors = ['blue', 'purple']
    xmlPrint(p)





More information about the Python-list mailing list