Still, constructing HTML in a script is a pretty common problem. It can end up looking pretty ugly, eg
'<a href="%s">Link</a>' % someurl
Punctuation soup, quotes in quotes. Consider that this little snippet of HTML is all within an entirely different language which is itself quite complex. I don't mind HTML on its own. I don't mind Python on its own. The combination is ugly.
There are also potential security pitfalls in not having automatic html escaping.
Many web toolkits avoid the whole problem by shuffling all the HTML off into "template" files. This is fine for big projects where you have a separate team of template designers, but is not great for small projects.
So how to do it right?
One can imagine a system that looked somewhat like this:
A('Link', href=url)
Or for the example in the link above:
Html(
Head(Title('Demo')) +
Body(
H1('Demo header') +
H3('Sub header') +
Font('The big dog & the little cat chased each other.'
size='+1', face='Times', color='#ffffff')
)
)
Note that Python's syntax forces parameters to go after the main text of an element. As a general rule the last parameter should be the most complex, and ideally it shouldn't be inside brackets -- a tail-recursion hack to avoid human-brain stack overflow. This may be partially ameliorated with a dash of curry, eg:
Font(face='Times',size='+1',color='#ffffff') \
('The big dog & the little cat chased each other.')
One thing Python et al have over HTML and XML is positional parameters. So my first example might simply read:
A('Link', url)
We're still talking big ugly expressions though. Suppose we break it down with a procedural approach. The following is longer, but more readable:
head = Title('Demo')
body = H1('Demo header')
body += H2('Sub header')
body += Font('Times','+1','#ffffff') \
('The big dog & the little cat chased each other.')
return Html(Head(head) + Body(body))
A final kink... Although Python doesn't support this, it would be nice to be able to re-order a procedure to take best advantage of the tail recursion brain-hack:
return Html(Head(head) + Body(body))
where:
head = Title('Demo')
body = H1('Demo header')
body += H2('Sub header')
body += Font('Times','+1','#ffffff') \
('The big dog & the little cat chased each other.')
See also: "Html Generation Packages" in this page. And Stan supports the currying trick.