Skip to content

Instantly share code, notes, and snippets.

@jstimpfle
Last active June 12, 2017 16:15
Show Gist options
  • Save jstimpfle/99ef75a43fea313a93141d3a11f30e62 to your computer and use it in GitHub Desktop.
Save jstimpfle/99ef75a43fea313a93141d3a11f30e62 to your computer and use it in GitHub Desktop.
Poor man's POWERFUL html templating system for python
import sys
class Element:
def __init__(self, name, **attributes):
self.name = name
self.attributes = attributes
self.childs = []
def setAttribute(self, key, val):
self.attributes[key] = val
def setAttributes(self, **kwargs):
for key, val in kwargs.items():
self.attributes[key] = val
def appendChild(self, child):
self.childs.append(child)
def writeHTML(self, out=None):
if out is None:
out = sys.stdout
out.write('<')
out.write(self.name)
for key, val in self.attributes.items():
# TODO: escaping
out.write(' %s="%s"' %(key, val))
out.write('>\n')
for child in self.childs:
child.writeHTML(out)
out.write('</')
out.write(self.name)
out.write('>\n')
def __enter__(self):
return NestingElements(self)
def __exit__(self, *args):
pass
class TextNode:
def __init__(self, text):
self.text = text
def writeHTML(self, out):
out.write(self.text
.replace('&', '&amp;')
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('"', '&quot;'))
def nest(self, nesting):
return nest(nesting, self)
class NestingElements:
def __init__(self, root_elem):
self.stack = [root_elem]
def get_root_elem(self):
assert len(self.stack) >= 1
return self.stack[0]
def get_current_elem(self):
assert len(self.stack) >= 1
return self.stack[-1]
def setAttribute(self, key, val):
self.get_current_elem().setAttribute(key, val)
def setAttributes(self, **kwargs):
self.get_current_elem().setAttributes(**kwargs)
def nest(self, elem):
return nest(self, elem)
def nestNewElem(self, *args, **kwargs):
return nest(self, Element(*args, **kwargs))
def addText(self, text):
self.get_current_elem().appendChild(TextNode(text))
class nest:
def __init__(self, nesting, elem):
self.nesting = nesting
self.elem = elem
self.nesting.stack[-1].appendChild(self.elem)
def __enter__(self):
self.nesting.stack.append(self.elem)
def __exit__(self, *args):
top = self.nesting.stack.pop()
assert top is self.elem
# Code:
# with Element('div') as ctx:
# with ctx.nestNewElem('ul'):
# with ctx.nestNewElem('li', style='border: 1px'):
# ctx.addText('Item 1')
# with ctx.nestNewElem('li'):
# ctx.addText('Item 2')
# ctx.get_root_elem().writeHTML()
#
# Output:
# <div>
# <ul>
# <li>
# Item 1</li>
# <li>
# Item 2</li>
# </ul>
# </div>
# test code...
class Person:
def __init__(self, firstname, lastname):
self.firstname = firstname
self.lastname = lastname
def comma_separated(elems):
out = []
for i, elem in enumerate(elems):
if i:
out.append(TextNode(', '))
out.append(elem)
return out
def formatPerson(person):
return TextNode('%s %s' %(person.firstname, person.lastname))
persons = [
Person('Joe', 'Doe'),
Person('Jane', 'Dane')
]
with Element('p') as ctx:
for elem in comma_separated(formatPerson(p) for p in persons):
ctx.nest(elem)
ctx.get_root_elem().writeHTML()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment