I have written this little tagging module to make it easier to generate small html snippets on the fly. The examples below show how this make things a bit easier. My question is about the handling of tags that contain either a single element like text or a list of other elements, like the tr element in the second example. At the moment, the code has to jump though some unpythonic loops to handle the different cases. How do I write code that handles either a single thing or a list of those things with one function in an elegant way?
""" Supplies some utilities for creating html documents manually
>>> print(h1('test'))
<h1>
test
</h1>
>>> print(table([tr([td('d1'), td('d2')]), tr()]))
<table>
<tr>
<td>
d1
</td>
<td>
d2
</td>
</tr>
<tr />
</table>
"""
from __future__ import print_function
class tag:
""" represents an html tag - specifically used to create outputs for web pages
Basic usage - create a "test" tag:
>>> print(tag('test'))
<test />
Attributes can be specified as a dictionary
>>> print(tag('test', attributes={'prop': 'value'}))
<test prop='value' />
The real benefit - tags can be nested, allowing the python interpreter to track closing tags:
>>> print(tag('test', tag('inner')))
<test>
<inner />
</test>
"""
def __init__(self, name, contents=[], attributes={}):
self.name = name
self.contents = contents
self.attributes = attributes
def __str__(self):
tagcontents = self.name
if len(self.attributes) > 0:
attrstring = " ".join("%s='%s'" % kv for kv in self.attributes.items())
tagcontents += " " + attrstring
if self.contents:
if hasattr(self.contents, '__iter__') and not hasattr(self.contents, 'strip'):
contentstring = "\n".join(str(i) for i in self.contents)
else:
contentstring = str(self.contents)
return "<%s>\n%s\n</%s>" % (tagcontents, contentstring, self.name)
else:
return "<" + tagcontents + " />"
def __repr__(self):
return "tag(%s, contents=%s, attributes=%s)" % (self.name, self.contents, self.attributes)
def namedtag(t):
""" create a named tag class - useful for standard html tags
>>> mytag = namedtag('mytag')
>>> print(mytag())
<mytag />
"""
class n(tag):
def __init__(self, contents=[], attributes={}):
tag.__init__(self, t, contents, attributes)
return n
h1, h2, p, table, td, th, tr, a = (namedtag(t) for t in ("h1", "h2", "p", "table", "td", "th", "tr", "a"))