CL-WHO in Python: clever or just stupid?
I can't tell if this is clever or just stupid. I like CL-WHO and I also like Python, so I've been fiddling with a way to mash the two up. W开发者_如何学编程hat I want is to say this:
tag("html",
lst(
tag("head"),
tag("body",
lst(
tag("h1", "This is the headline"),
tag("p", "This is the article"),
tag("p",
tag("a", "Click here for more", ["href", "http://nowhere.com"]))))))
and have it evaluate to this:
<html>
<head>
</head>
<body>
<h1>This is the headline</h1>
<p>This is the article</p>
<p>
<a href="http://nowhere.com">Click here for more</a>
</p>
</body>
</html>
Looks just like CL-WHO but with function notation instead of s-expressions. So I started with this tag-generating function:
def tag(name, inner="", attribs=[], close=True):
ret = []
ret.append('<' + name)
while attribs.__len__() > 0:
ret.append(' %s="%s"' % (attribs.pop(0),attribs.pop(0)))
ret.append(">")
if type(inner).__name__ == 'list':
ret.extend(inner)
else:
ret.append(inner)
if close:
ret.append('</%s>' % name)
return "".join(ret)
inner can be a list and square brackets for lists are ugly in all that Lispy code, so I want a function that makes a list from its arguments:
def lst(*args):
return [x for x in args]
To facilitate conditional code generation, you need an if statement which is a function that evaluates to one of two results, as in Lisp, so you can nest it. An imperative flow- control-style if will not do.
def fif(cond, a, b):
if cond:
return a
else:
return b
Vioila. Now you can generate a sample page like this:
def gen(x):
"""Sample function demonstratine conditional HTML generation. Looks just like CL-WHO!"""
return tag("html",
lst(
tag("head"),
tag("body",
lst(
fif(x == 1, tag("h1", "This is the headline"), tag("h1", "No, THIS is the headline")),
tag("p", "This is the article"),
tag("p",
tag("a", "Click here for more", ["href", "http://nowhere.com"]))))))
print gen(1)
Where this starts to break down is loops. Anything that loops is going to have to be extracted into a separate function. So what dio you think? Interesting or dumb? Try it & tell me what you think.
You should html-escape every text node, attribute value, etc. or html injection and XSS will bite you.
Apart from full-featured templating systems (mako, genhi, chameleon, jinja, etc) the library more similar to what you do is probably lxml
>>> from lxml.html.builder import HTML, HEAD, BODY, H1, P, A
>>> from lxml.html import tostring
>>>
>>> h = HTML(
... HEAD(
... BODY(
... H1('This is the headline'),
... P('This is the article'),
... P(
... A('Click here for more', href='http://nowhere.com')))))
>>> print tostring(h, pretty_print=True)
<html><head><body>
<h1>This is the headline</h1>
<p>This is the article</p>
<p><a href="http://nowhere.com">Click here for more</a></p>
</body></head></html>
And you can use the ternary operator
H1("This is the headline" if x==1 else "No, THIS is the headline")
精彩评论