00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 HTML4_STRICT = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
00036 HTML4_TRANS = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
00037 HTML4_FRAMES = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
00038 XHTML4_STRICT = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
00039 XHTML4_TRANS = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
00040 XHTML4_FRAMES = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
00041
00042 SELF_CLOSING_TAGS = ['br', 'img', 'hr', 'meta', 'link', 'input']
00043
00044 from elementtree.SimpleXMLWriter import XMLWriter
00045 from cStringIO import StringIO
00046
00047 try:
00048 from tidy import parseString
00049 except ImportError:
00050 def parseString(text):
00051 return text
00052
00053 def _iterelement( element ):
00054 '''
00055 returns all lists from a list of lists
00056 '''
00057 for item in element:
00058 yield item
00059 if len(item) > 0:
00060 for subitem in _iterelement( item ):
00061 yield subitem
00062
00063 class _HtmlWriter(XMLWriter, object):
00064
00065
00066
00067
00068
00069
00070
00071
00072 def data( self, text ):
00073 '''write htmlentity-encoded text'''
00074 super( _HtmlWriter, self).data(text)
00075 self._XMLWriter__flush()
00076
00077
00078
00079
00080 def write(self, text):
00081 '''write raw, ie. unescaped, text'''
00082 if self._XMLWriter__open:
00083 self._XMLWriter__open = 0
00084 self._XMLWriter__write( '>' )
00085 self._XMLWriter__write(text)
00086
00087 class _HtmlElement(list):
00088
00089 def __init__(self, tag):
00090 self.tag = tag
00091 self.innertext = None
00092 self.attrib = {}
00093
00094 def __call__(self, innertext='', **kwargs):
00095 self.innertext = innertext
00096 self.attrib = kwargs
00097 return self
00098
00099 def __repr__(self):
00100 return "<_HtmlElement %s at %x>" % (self.tag, id(self))
00101
00102 def append(self, value):
00103 super(_HtmlElement,self).append(value)
00104 return value
00105
00106 def insert(self, index, value):
00107 super(_HtmlElement,self).insert(value)
00108 return value
00109
00110 def __getattr__(self, value):
00111 try:
00112 elmnt = types[value]()
00113 except KeyError:
00114 elmnt = _HtmlElement(value)
00115 return self.append( elmnt )
00116
00117 def _write(self, writer):
00118
00119
00120 cssClass = None
00121 for key in self.attrib.iterkeys():
00122 if key in ['css','class_','cssClass']:
00123 cssClass = self.attrib[key]
00124 del self.attrib[key]
00125 break
00126 if cssClass is not None:
00127 self.attrib['class'] = cssClass
00128
00129 if self.tag in SELF_CLOSING_TAGS:
00130 writer.element( self.tag, None, self.attrib )
00131
00132 for node in self:
00133 node._write(writer)
00134 else:
00135 writer.start(self.tag, self.attrib)
00136 if self.innertext is not None:
00137 writer.data(self.innertext)
00138
00139 for node in self:
00140 node._write(writer)
00141 writer.end()
00142
00143 def write(self, outfile ):
00144 w = _HtmlWriter(outfile)
00145 self._write( w )
00146
00147 def __str__(self):
00148 s = StringIO()
00149 self.write( s )
00150 ret = s.getvalue()
00151 s.close()
00152 return ret
00153
00154 def tidy(self):
00155 return str(parseString( self.__str__() ))
00156
00157 def tidywrite(self, outfile):
00158 outfile.write( self.tidy() )
00159
00160 def fill( self, searchList ):
00161 for t in _iterelement( self ):
00162 if hasattr( t, 'fill' ):
00163 t.fill( searchList )
00164
00165 def __mod__(self, searchList):
00166 self.fill(searchList)
00167 return self
00168
00169 def __imod__(self, searchList):
00170 self.fill(searchList)
00171 return self
00172
00173 class _HtmlText(_HtmlElement):
00174 def __init__(self, innertext=''):
00175 self.innertext = innertext
00176
00177 def __call__(self, innertext=''):
00178 self.innertext = innertext
00179 return self
00180
00181 def __repr__(self):
00182 return "<_HtmlText at %x>" % id(self)
00183
00184 def _write(self, writer):
00185 writer.data( self.innertext )
00186 for child in self:
00187 child._write(writer)
00188
00189 class _HtmlLiteral(_HtmlText):
00190
00191 def __repr__(self):
00192 return "<_HtmlLiteral at %x>" % id(self)
00193
00194 def _write(self, writer):
00195 writer.write( self.innertext )
00196 for child in self:
00197 child._write(writer)
00198
00199 class _HtmlComment(_HtmlText):
00200
00201 def __repr__(self):
00202 return "<_HtmlComment at %x>" % id(self)
00203
00204 def _write( self, writer, indent=0 ):
00205 writer.write('\n')
00206 writer.comment( self.innertext )
00207 writer.write('\n')
00208 for child in self:
00209 child._write(writer)
00210
00211 class _HtmlIncludeFile(_HtmlElement):
00212
00213 def __repr__(self):
00214 return "<_HtmlIncludeFile %s at %x>" % (self.filepath[10:], id(self))
00215
00216 def __init__(self, path=None):
00217 self.filepath = path
00218
00219 def __call__( self, path=None ):
00220 self.filepath = path
00221 return self
00222
00223 def _write(self, writer):
00224 infile = open(self.filepath, 'r')
00225 try:
00226 for line in infile:
00227 writer.write( line )
00228 finally:
00229 infile.close()
00230 for child in self:
00231 child._write(writer)
00232
00233 class _HtmlPlaceholder(_HtmlElement):
00234
00235 def __repr__(self):
00236 return "<_HtmlPlaceholder %s at %x>" % ( self.name, id(self) )
00237
00238 def __init__(self, name='', format='%s', searchList=None):
00239 self.name = name
00240 self.format = format
00241 self.innertext = None
00242 self.rawtext = None
00243 if searchList:
00244 self.fill( searchList )
00245
00246 def __call__(self, name, format='%s', searchList=None):
00247 self.__init__(name, format, searchList)
00248 return self
00249
00250 def fill( self, searchList ):
00251 name = self.name
00252 for item in searchList:
00253 if isinstance( item, dict ):
00254 value = item.get( name )
00255 if value is not None:
00256 if isinstance( value, str ):
00257 self.innertext = value
00258 self.rawtext = None
00259 else:
00260
00261
00262
00263
00264
00265 self.rawtext = self.format % str(value)
00266 self.innertext = None
00267 break
00268
00269 def __mod__(self, searchList):
00270 self.fill( searchList )
00271 return self
00272
00273 def __imod__(self, searchList):
00274 return self.__mod__(searchList)
00275
00276 def _write(self, writer):
00277 if self.innertext is not None:
00278 writer.data(self.innertext)
00279 elif self.rawtext is not None:
00280 writer.write(self.rawtext)
00281 else:
00282 s = ''.join( [ ' %(', self.name, ')', self.format[1:], ' ' ] )
00283 writer.data( s )
00284 for child in self:
00285 child._write(writer)
00286
00287 class _CheetahTemplate(_HtmlPlaceholder):
00288
00289 def __repr__(self):
00290 return "<_CheetahTemplate at %x>" % id(self)
00291
00292 def __init__(self, source=None, searchList=None, file=None, name='CHEETAH'):
00293 super(_CheetahTemplate, self).__init__( name, format='%s' )
00294 self.source = source
00295 self.file = None
00296 if searchList:
00297 self.fill( searchList )
00298
00299 def __call__(self, source=None, searchList=None, file=None, name='CHEETAH'):
00300 self.__init__(source, searchList, file, name)
00301 return self
00302
00303 def fill(self, searchList):
00304 from Cheetah.Template import Template
00305 t = Template( source=self.source, searchList=searchList, file = self.file )
00306 self.rawtext = str( t )
00307
00308 class _HtmlPythonSource(_HtmlIncludeFile):
00309
00310 def __repr__(self):
00311 return "<_HtmlPythonSource at %x>" % id(self)
00312
00313 def _write(self, writer):
00314 from colorizer import HtmlColorizer
00315 if self.filepath is not None:
00316 c = HtmlColorizer(self.filepath, writer)
00317 c.colorize()
00318 for child in self:
00319 child._write(writer)
00320
00321 class _HtmlPage(_HtmlElement):
00322
00323 def __init__(self, title='', doctype=HTML4_STRICT, styles=[]):
00324 self.title = title
00325 self.stylesheets = styles
00326 self.styleblocks = []
00327 self.doctype = doctype
00328
00329 def __repr__(self):
00330 return "<_HtmlPage %s at %x>" % (self.title, id(self))
00331
00332 def __call__(self, title='', doctype=HTML4_STRICT, styles=[]):
00333 self.__init__( title, doctype, styles )
00334 return self
00335
00336 def _write(self, writer):
00337 writer.write(self.doctype+'\n')
00338 writer.start( "html" )
00339 writer.start( "head" )
00340 writer.element( "title", self.title )
00341 for url in self.stylesheets:
00342 writer.element( "link", rel="stylesheet", type="text/css", href="%s" % url )
00343 for style in self.styleblocks:
00344 writer.start( "style", type="text/css" )
00345 writer.data( style )
00346 writer.end()
00347 writer.end()
00348 writer.start("body")
00349 for node in self:
00350 node._write(writer)
00351 writer.end()
00352 writer.end()
00353
00354 types = { 'text': _HtmlText,
00355 'literal': _HtmlLiteral,
00356 'comment': _HtmlComment,
00357 'include': _HtmlIncludeFile,
00358 'python': _HtmlPythonSource,
00359 'placeholder': _HtmlPlaceholder,
00360 'cheetah': _CheetahTemplate,
00361 'page': _HtmlPage
00362 }
00363
00364 class _HtmlBuilder(object):
00365 '''a factory class for creating _HtmlElements '''
00366 def __getattr__(self, value, *args, **kwargs):
00367 try:
00368 return types[value]( *args, **kwargs )
00369 except KeyError:
00370 return _HtmlElement(value)
00371
00372
00373 html = _HtmlBuilder()
00374
00375
00376 if __name__ == '__main__':
00377 page = html.page('Test Page')
00378 page.styleblocks.append( 'p {color:black}\nbody {font-family:courier}' )
00379 page.comment('Begin Header')
00380 page.placeholder('HEADER')
00381 page.comment('Begin Content')
00382 page.placeholder('CONTENT')
00383 page.comment('Begin Footer')
00384 page.placeholder('FOOTER')
00385
00386 header = html.h1( 'header here' )
00387 header.literal('<img src="dddd" />')
00388 content = html.div(id='content', css='main')
00389 content.h3('Welcome ').placeholder('USER').text('!!')
00390 content.hr
00391 links = content.ul(css='navbar')
00392 links.li.a( 'Home', href='/home.html' )
00393 links.li.a( 'Find Page', href='/FindPage.html' )
00394 links.li.a( 'Recent Changes', href='/RecentChanges.html' )
00395
00396 footer = html.div(id='footer')
00397 try:
00398 from Cheetah.Template import Template
00399 footer.cheetah('Cheetah says the date is $DATE')
00400 except:
00401 footer.text('The date is ').placeholder('DATE')
00402
00403 import time
00404 ts = time.asctime(time.localtime())
00405
00406 content %= [{ 'USER': 'Arthur Dent' }]
00407 footer %= [{ 'DATE': ts }]
00408 page %= [{ 'HEADER': header, 'CONTENT': content, 'FOOTER': footer }]
00409
00410 print '-' * 80
00411 print 'Using print'
00412 print '-' * 80
00413 print page
00414 print
00415 print '-' * 80
00416 print 'Using write()'
00417 print '-' * 80
00418 import sys
00419 page.write(sys.stdout)
00420 print
00421 print '-' * 80
00422 print 'Using tidywrite()'
00423 print '-' * 80
00424 page.tidywrite(sys.stdout)