00001 
00002 from elementtree.SimpleXMLWriter import XMLWriter
00003 from cStringIO import StringIO
00004 
00005 class _XmlElement(list):
00006     def __init__(self, tag):
00007         self.tag = tag
00008         self.text = None
00009         self.attrib = {}
00010 
00011     def __call__(self, text='', **kwargs):
00012         self.text = text
00013         self.attrib = kwargs
00014         return self
00015 
00016     def __repr__(self):
00017         return "<_XmlElement %s>" % self.tag
00018 
00019     def append(self, value):
00020         list.append(self, value)
00021         return value
00022 
00023     def __getattr__(self, value):
00024         if value == "add_comment":
00025             return self.append( _XmlComment() )
00026         elif value == "add_text":
00027             return self.append( _XmlText() )
00028         else:
00029             return self.append( _XmlElement(value) )
00030 
00031     def _write(self, writer):
00032         #class is a keyword, so can't use it as an attribute name
00033         #use 'class_' then replace it here
00034         class_ = None
00035         for key in self.attrib.iterkeys():
00036             if key == 'class_':
00037                 class_ = self.attrib[key]
00038                 del self.attrib[key]
00039                 break
00040         if class_ is not None:
00041             self.attrib['class'] = class_
00042         #now write this element
00043         if not self.__len__() and not self.text:
00044                 writer.element( self.tag, None, self.attrib )
00045         else:
00046             writer.start(self.tag, self.attrib)
00047             if self.text is not None:
00048                 writer.data(self.text)
00049             #write any children if any
00050             for node in self:
00051                 node._write(writer)
00052             writer.end()
00053 
00054 class _XmlText(_XmlElement):
00055 
00056     def __init__(self):
00057         self.text = ''
00058 
00059     def __call__(self, text=''):
00060         self.text = text
00061         return self
00062 
00063     def _write(self, writer):
00064         writer.data(self.text)
00065         for node in self:
00066             node._write(writer)
00067 
00068     def __repr__(self):
00069         return "<_XmlText>"
00070 
00071 class _XmlComment(_XmlText):
00072 
00073     def _write(self, writer):
00074         writer.comment(self.text)
00075 
00076     def __repr__(self):
00077         return "<_XmlComment>"
00078 
00079 class XmlFragment(_XmlElement):
00080     '''
00081     >>> xml = XmlFragment()
00082     >>> root = xml.div()
00083     >>> print root
00084     <_XmlElement div>
00085     >>> print xml
00086     <div />
00087     >>> firstchild = root.p("Some text", id="1")
00088     >>> print xml
00089     <div><p id="1">Some text</p></div>
00090     >>> firstchild.br()
00091     <_XmlElement br>
00092     >>> print xml
00093     <div><p id="1">Some text<br /></p></div>
00094     >>> firstchild.add_text("more text, ")
00095     <_XmlText>
00096     >>> print xml
00097     <div><p id="1">Some text<br />more text, </p></div>
00098     >>> firstchild.add_text("and more.").br()
00099     <_XmlElement br>
00100     >>> print xml
00101     <div><p id="1">Some text<br />more text, and more.<br /></p></div>
00102     >>> root.add_comment("COMMENT")
00103     <_XmlComment>
00104     >>> print xml
00105     <div><p id="1">Some text<br />more text, and more.<br /></p><!-- COMMENT -->
00106     </div>
00107     '''
00108     def __init__(self, encoding="utf-8"):
00109         self.encoding = encoding
00110 
00111     def _write(self, writer):
00112         for node in self:
00113             node._write(writer)
00114 
00115     def write(self, outfile):
00116         w = XMLWriter(outfile, self.encoding)
00117         self._write( w )
00118 
00119     def __str__(self):
00120         s = StringIO()
00121         self.write( s )
00122         ret = s.getvalue()
00123         s.close()
00124         return ret
00125 
00126 class MissingDocumentRootException(Exception): pass
00127 
00128 class XmlDocument(XmlFragment):
00129     '''
00130     >>> xml = XmlDocument("us-ascii")
00131     >>> print xml
00132     Traceback (most recent call last):
00133         ...
00134     MissingDocumentRootException
00135     >>> root = xml.items(catalog="R&D")
00136     >>> print xml
00137     <?xml version='1.0'?>
00138     <items catalog="R&amp;D" />
00139     >>> root.item("Item 1", id="1")
00140     <_XmlElement item>
00141     >>> root.item("Item 2", id="2")
00142     <_XmlElement item>
00143     >>> print xml
00144     <?xml version='1.0'?>
00145     <items catalog="R&amp;D"><item id="1">Item 1</item><item id="2">Item 2</item></items>
00146     '''
00147     def _write(self, writer):
00148         if not len(self):
00149             raise MissingDocumentRootException
00150         writer.declaration()
00151         for node in self:
00152             node._write(writer)
00153 
00154 def _test():
00155     import doctest
00156     doctest.testmod()
00157 
00158 if __name__ == '__main__':
00159     _test()