166 lines
12 KiB
HTML
166 lines
12 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<title>CLiki: html-template</title>
|
||
|
<link rel="alternate" type="application/atom+xml" title="ATOM feed of edits to current article"
|
||
|
href="https://www.cliki.net/site/feed/article.atom?title=html-template">
|
||
|
<link rel="stylesheet" href="static/css/style.css">
|
||
|
<link rel="stylesheet" href="static/css/colorize.css">
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<span class="hidden">CLiki - html-template</span>
|
||
|
<div id="content"><div id="content-area"><div id="article-title">html-template</div><div id="article">HTML-TEMPLATE is an <a href="HTML template.html" class="category">HTML template</a> library to use templates much like Perl's <a href="https://metacpan.org/pod/HTML::Template">HTML::Template</a>. Despite its name, HTML-TEMPLATE is HTML-agnostic and could be used for templating other documents.<p>It was written by <a href="Edi Weitz.html" class="internal">Edi Weitz</a> and can be found at <a href="https://edicl.github.io/html-template/">https://edicl.github.io/html-template/</a>.<p><a href="Jörg Höhle.html" class="internal">Jörg Höhle</a> also liked the idea of a <em> clear and complete
|
||
|
separation between HTML</em> (written by designers) and code. He
|
||
|
came up with a variant of Edi's approach to HTML template. It uses
|
||
|
Edi's parsing code (thanks!), no more, but the programmer view on it
|
||
|
<em>feels very different</em>.<p>Consider Edi's 7x7 chess board example on his documentation page and
|
||
|
how my code would look like:<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> my-template
|
||
|
<span class="comment">;; load and check against specification
|
||
|
</span> <span class="paren2">(<span class="nonparen">tmpl-load <span class="string">"file.html"</span> '<span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">LOOP</span></i></a> rows <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">LOOP</span></i></a> cols colorful-style content</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
|
||
|
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">counter 0</span>)</span></span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen">tmpl-print
|
||
|
my-template
|
||
|
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_lambda.html" class="symbol"><i><span class="symbol">lambda</span></i></a> <span class="paren4">(<span class="nonparen">rowprinter</span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> repeat 7 <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a>
|
||
|
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_funcall.html" class="symbol">funcall</a> rowprinter
|
||
|
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_lambda.html" class="symbol"><i><span class="symbol">lambda</span></i></a> <span class="paren1">(<span class="nonparen">cellprinter</span>)</span>
|
||
|
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> repeat 7 <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a>
|
||
|
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_funcall.html" class="symbol">funcall</a> cellprinter <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_evenpcm_oddp.html" class="symbol">oddp</a> counter</span>)</span> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> <span class="string">"~R"</span> counter</span>)</span></span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_incfcm_decf.html" class="symbol">incf</a> counter</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
</span></div><p><a href="Jörg Höhle.html" class="internal">Jörg Höhle</a>'s design goals:
|
||
|
<ul><p> <li> Separate HTML design from code as much as possible, the key
|
||
|
idea in the template approach.<p> </li>
|
||
|
<li> <em>Verifiable specification</em> of the interface between
|
||
|
both, never see "$foo" in a user's browser as an indication that
|
||
|
some variable was not substituted.<p> </li>
|
||
|
<li> Designer and programmer <em>work concurrently</em> early
|
||
|
on. The programmer may use a default template automatically derived
|
||
|
from the specification, the web-designer a random-content template
|
||
|
delivering web-server based on this specification.<p> </li>
|
||
|
<li> <em>Efficiently deliver data</em>, which should be no
|
||
|
slower than frameworks based on direct embedding of code in <a href="HTML.html" class="internal">HTML</a> or
|
||
|
vice-versa. That's why I rejected intermediate structures (Edi's <a href="https://edicl.github.io/html-template/#semantics">template
|
||
|
structure</a>) and produce compilable code. A parsed template
|
||
|
becomes Lisp code, which can be either compiled and loaded as such
|
||
|
from the file system, or compiled on the fly at load-time.<p> </li>
|
||
|
<li> <em>Incrementally deliver results</em> as produced (useful
|
||
|
for huge data or HTTP 1.1 chunked encoding) which is incompatible
|
||
|
with non-lazy intermediate structures.<p> </li>
|
||
|
<li> Provide for <em>lexical scoping in templates</em>,
|
||
|
unlike Perl's HTML::Template. That is, a <samp>TMPL_VAR</samp> occurring
|
||
|
inside <samp>TMPL_LOOP</samp> may reference variables defined in an
|
||
|
outer (e.g. global) level. There's no need to repeat definitions at
|
||
|
inner levels.<p> </li>
|
||
|
<li> Deliver data in pieces as large as possible: i.e. no individual
|
||
|
calls to <a href="https://www.cliki.net/site/HyperSpec/Body/fun_writecm_p_rintcm_princ.html" class="hyperspec">PRINC</a> or <a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="hyperspec">FORMAT</a> for each HTML tag, coalesce these
|
||
|
instead.<p> </li>
|
||
|
<li> Early HTML validation of the templates
|
||
|
</li>
|
||
|
<li> some more I forgot...<p></li>
|
||
|
</ul><p>[This next section confuses me a bit. I think a list entry refers to Edi's version, but I can't really tell.]
|
||
|
Some differences between Edi and Jörg's work include:
|
||
|
<ul>
|
||
|
<li> No <tt>TMPL_INCLUDE</tt>
|
||
|
</li>
|
||
|
<li> No facility for caching or automated reloading, which I feel
|
||
|
orthogonal to templates, interferes with
|
||
|
<tt>TMPL_INCLUDE</tt> and is left to the application.
|
||
|
</li>
|
||
|
<li> An attempt to load templates validates them, so the running
|
||
|
web-server application will choose to reject template updates (and
|
||
|
log the error) until they are corrected instead of displaying
|
||
|
garbage to the user.
|
||
|
</li>
|
||
|
<li> <tt>TMPL_VAR</tt> may have content, which is valuable for
|
||
|
the web designer's <a href="GUI.html" class="internal">GUI</a>: s/he sees this content up to a closing
|
||
|
<tt>/TMPL_VAR</tt>.
|
||
|
</li>
|
||
|
<li> Variable substitution on the code side is <em>based on ordering
|
||
|
in the specification</em>, not on names or symbols, so there are no
|
||
|
surprises with packages and symbol-names across files.
|
||
|
</li>
|
||
|
<li> The template substituting code is trivially small and was
|
||
|
ported to Scheme. In fact, there's almost no such code since it's
|
||
|
in part in the programmer calling sequence (witness the above
|
||
|
example) and part in the Lisp code representing the template.
|
||
|
</li>
|
||
|
<li> Edi's got a package ready to go for you. [So is there code somewhere interested people could hack on, or something?]
|
||
|
</li>
|
||
|
</ul><p>My experience:
|
||
|
<ul>
|
||
|
<li> The above specification is not all about the interface between
|
||
|
programmer and designer. URL structure, form names etc. need also
|
||
|
be agreed upon.
|
||
|
</li>
|
||
|
<li> The template approach is <em>very useable</em> for
|
||
|
applications with <strong>small or medium demand for variable
|
||
|
appearance</strong>. Or you'd need too many templates.
|
||
|
</li>
|
||
|
<li> I generated pages using templates featuring <strong>highly
|
||
|
dynamic content</strong> (e.g. variable numbers of both rows and
|
||
|
colums of a table, selectable and variable order) which some people
|
||
|
initially thought not usable with a strict templates approach. It
|
||
|
was, in fact, clean and easy.
|
||
|
</li>
|
||
|
<li> <samp>TMPL_LOOP</samp> and <samp>TMPL_VAR</samp> are really
|
||
|
general and could even emulate <samp>TMPL_IF</samp>.
|
||
|
</li>
|
||
|
<li> I generated my templates from Lisp code via SXML, instead of
|
||
|
having a designer. This aids consistency among templates. For a
|
||
|
all-by-one-person job, the separation is clear overhead, even if
|
||
|
there's potential for code reuse. You'd probably prefer a
|
||
|
<a href="htout.html" class="internal">HTML-from-sexpr</a> approach in such a case and bypass templates.
|
||
|
</li>
|
||
|
<li> <em>HTML validation</em> of the templates is hindered by
|
||
|
<samp>TMPL_IF</samp> with an <samp>ELSE</samp> part, substitutions
|
||
|
inside attributes and obviously only possible when the
|
||
|
substitutions done by <samp>TMPL_VAR</samp> affect the HTML
|
||
|
structure. The most dynamic template is <kbd>TMPL_VAR
|
||
|
make-it-all</kbd>!<p> </li>
|
||
|
<li> As an enhancement, there could be a mechanism for global
|
||
|
substitutions which would remain outside of the specification.
|
||
|
E.g. some pages like to display calendars, the current date or use
|
||
|
a mapping from month names to numbers etc. Such substitutions could
|
||
|
always be present, across all pages of the application.
|
||
|
</li>
|
||
|
</ul></div></div>
|
||
|
<div id="footer" class="buttonbar"><ul><li><a href="html-template.html">Current version</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/history?article=html-template">History</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/backlinks?article=html-template">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=html-template&from-revision=3830186510">Edit</a></li><li><a href="https://www.cliki.net/site/edit-article?create=t">Create</a></li></ul></div>
|
||
|
</div>
|
||
|
<div id="header-buttons" class="buttonbar">
|
||
|
<ul>
|
||
|
<li><a href="https://www.cliki.net/">Home</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/recent-changes">Recent Changes</a></li>
|
||
|
<li><a href="CLiki.html">About</a></li>
|
||
|
<li><a href="Text Formatting.html">Text Formatting</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/tools">Tools</a></li>
|
||
|
</ul>
|
||
|
<div id="search">
|
||
|
<form action="https://www.cliki.net/site/search">
|
||
|
<label for="search_query" class="hidden">Search CLiki</label>
|
||
|
<input type="text" name="query" id="search_query" value="" />
|
||
|
<input type="submit" value="search" />
|
||
|
</form>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div id="pageheader">
|
||
|
<div id="header">
|
||
|
<span id="logo">CLiki</span>
|
||
|
<span id="slogan">the common lisp wiki</span>
|
||
|
<div id="login"><form method="post" action="https://www.cliki.net/site/login">
|
||
|
<label for="login_name" class="hidden">Account name</label>
|
||
|
<input type="text" name="name" id="login_name" class="login_input" />
|
||
|
<label for= "login_password" class="hidden">Password</label>
|
||
|
<input type="password" name="password" id="login_password" class="login_input" />
|
||
|
<input type="submit" name="login" value="login" id="login_submit" /><br />
|
||
|
<div id="register"><a href="https://www.cliki.net/site/register">register</a></div>
|
||
|
<input type="submit" name="reset-pw" value="reset password" id="reset_pw" />
|
||
|
</form>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</body></html>
|