Here, 'objal is a macro that makes association lists tagged with the type 'al. The 'al type is then treated specially by functions like '<a. I think your arglist-parsing is much more convenient, but maybe there could be a hybrid or something. I like having the potential to use utilities other than 'objal for constructing attribute lists.
The other main difference is that my custom type for HTML tags actually has four parts: not only the name, the attribute list, and the body, but also another value to hold explicit rendering hints and overrides. For instance, I can make a tag so that it's rendered as though its content is preformatted (i.e. like the <pre> tag), even if other tags of the same name don't have the same behavior. This would matter more if I actually had a pretty-printer. :-p
Speaking of pretty-printers, one thing overlooked by a lot of HTML generators, including yours, is that whitespace between a tag and its contents can often matter. For instance, this HTML...
Visit the
<a href="http://arclanguage.org/">
Arc Forum
</a>
today!
...renders as "Visit the (Arc Forum )today!", where my parentheses indicate the extent of the hyperlink. This is everywhere on the Web, but IMO it's pretty sloppy.
In my manually-written HTML, I've actually opted for this sort of code when I'm desperate to indent things a certain way:
Visit the
<a href="http://arclanguage.org/"><!--
-->Arc Forum<!--
--></a>
today!
I've recently been tending toward other, less consistent but more readable techniques, like this one:
Visit the
<a href="http://arclanguage.org/"
>Arc Forum</a>
today!
(This is also way more convenient when the need arises to comment out a whole section of the page.)
But right now, my generator just puts everything on one line, which also works. :-p
FYI, since your system prints each node on a separate line, it's impossible for a node to not have whitespace around it. For instance:
(deftag italic
(tag "i" args))
; idiomatic, but rendered with incorrect spacing
(= rocketnia* (list "Rocket-N" (italic "I") "A"))
; workaround
(= rocketnia* "Rocket-N<i>I</i>A")
; incorrect... but no workaround?
(def manually-quote (html)
(list "\"" html "\""))
The all-output-on-one-line approach could help here too.
I'm definitely a fan of this 'annotate approach to building HTML. I like the idea that as the framework gets more refined, it might be possible to output the same page as either HTML or XHTML with just a configuration change.
You have a good point about the rendering oddities with whitespace. There's a lot of room for improvement here. Rendering hints would definitely be nice. For instance, <link> and <input> tag don't typically close themselves. And tags like <a> <b> <u> <em> should just print on a single line.
> I'm definitely a fan of this 'annotate approach to building HTML. I like the idea that as the framework gets more refined, it might be possible to output the same page as either HTML or XHTML with just a configuration change.
haha, I didn't quite think of this at the beginning.
My 'render-html is completely decoupled from the building of the HTML. It's just one type of a printer, and it likes to pretty-print things for readability.
We could add easily imagine adding several more printers, and even a system for registering and choosing one, with 'render-html being merely an alias to the chosen one.
...perhaps it's a good thing that rendering hints aren't part of the tag object.
I have tag-by-tag hints in mine just in case I want two otherwise identical HTML tags to have different rendering behavior, for a browser hack or something. Eventually I do hope to have an 'html hint that causes the element's tag name to be looked up in the renderer's HTML specification of choice, but I may still want to leave that hint out occasionally just to have better control.
Actually, it could just be a matter of laziness. The only hint I use right now is 'collapsible, which I put on the <meta> and <link> tags so that they don't have closing tags when their contents are empty. Since it's only one hint, I haven't bothered to make a whole extensible system based on objects that represent HTML specifications.
Oh hell, I'm not writing a complete system for html specs. Just a quick hack for the most commonly used tags and the way I think they work.
For that matter, I didn't know link and meta could have content.
I changed the rendering engine to print some tags inline and self-close some tags.
(render-html (page 'title "Test" 'js "js.js" 'css "css.css"
(p "Hello world" (e 'em "emhasis!!!") "did you see that?")
(p "Btw, this is" (e 'a 'href "google.com" "mylink"))))
<!doctype html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="js.js"></script>
<link rel="stylesheet" type="text/css" href="css.css" />
</head>
<body>
<p>Hello world <em>emhasis!!!</em> did you see that?</p>
<p>Btw, this is <a href="google.com">mylink</a></p>
</body>
</html>
> I have tag-by-tag hints in mine just in case I want two otherwise identical HTML tags to have different rendering behavior
The tag object is just a hashtable, you can always hack it and insert whatever custom attributes you want, and then use these as rendering hints in the rendering engine/function.
Oh hell, I'm not writing a complete system for html specs.
I sort of am, but only in the very long term. It can start as a tiny type that just holds its own specific special-casing behavior, and then it can grow in complexity as complexity is needed. That said, it may be difficult to predict what behavior is specific to a single HTML specification until one's tried to provide a choice between multiple specs.
I changed the rendering engine to print some tags inline and self-close some tags.
Awesome. :D
For that matter, I didn't know link and meta could have content.
They're not supposed to. (It would be interesting to look at the DOM to see if they can in practice.) I'm talking about when I might potentially want to give them content for a weird browser-specific hack.
The tag object is just a hashtable, you can always hack it and insert whatever custom attributes you want, and then use these as rendering hints in the rendering engine/function.