Dynamicly generated websites in Erlang

Kent Boortz <>
Wed Mar 28 22:23:18 CEST 2001


Chris Pressey <> writes:
> Assuming you can coerce INETS into doing what you want, you might want
> to check out Joe Armstrong's EHTML contribution as a solution for your
> template feature.  It allows you to define new HTML tags, and to embed
> Erlang directly in the template.

Ehtml is what is used for most parts of www.erlang.org but we don't use
it dynamically. We use it together with Unix make and Erlang ermake
to generate the pages before we rsync them over from our internal net
to www.erlang.org.

The erlang code to embed is funs (maybe I haven't read the manual
closely enough but I don't think you can use named functions). It is
an interesting challenge to express what you want to do using no named
functions. I include the current included file with new tag
definitions used at www.erlang.org as an example. Maybe a bit ugly but
it works and is reasonable easy to change or extend. I like the idea
generating pages only when changed, not for every server request,

kent


<def name="header">
fun(Args, Str) ->
% Find the relative path to the top directory of the HTML tree
  RelPath =
    case lists:keysearch("path_to_top", 1, Args) of
      {value,{_,""}} ->
        "";
      false ->
        "";
      {value,{_,"/"}} ->
	"/";
      {value,{_,Value}} ->
        filename:join(filename:split(Value)) ++ "/"
    end,
["
<!-- Form around whole table to avoid Netscape space after form problem -->
<form action=\"http://www.erlang.org/cgi-bin/se_search\" method=\"get\">
  <input type=\"hidden\" name=\"data\" value=\"search_index\">
  <input type=\"hidden\" name=\"result_max\" value=\"10\">

<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">
  <tr>
    <td bgcolor=\"#336699\" width=\"1%\" align=\"left\"><a href=\"http://www.ericsson.se\"><img src=\"",RelPath,"images/erilogo.gif\" alt=\"Ericsson\" border=\"0\" width=\"123\" height=\"34\"></a></td>
    <td bgcolor=\"#336699\" align=right><font face=\"Helvetica,Ariel\" size=+2 color=\"#FFFFFF\">Open Source Erlang</font></td>
    <td bgcolor=\"#336699\" width=\"1%\" valign=\"top\" align=\"right\"><img src=\"",RelPath,"images/corner.gif\" alt border=\"0\" width=\"10\" height=\"34\"></td>
  </tr>
  <tr>
    <td bgcolor=\"#ADD8E6\" height=\"30\" align=\"left\" valign=\"middle\">
      <b><font face=\"Helvetica,Ariel\" size=\"2\" color=\"#336699\">  Ericsson Utvecklings AB</font></b>
    </td>
    <td bgcolor=\"#ADD8E6\" height=\"30\" align=\"right\" valign=\"bottom\">
	<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">
	  <tr>
	    <td valign=\"middle\" height=\"20\">
              <font face=\"Helvetica,Ariel\" size=\"2\" color=\"#336699\">
		<a href=\"http://www.erlang.org/search/\">Search</a> 
	      </font>
	    </td>
	    <td valign=\"middle\" height=\"20\">
	      <font face=\"Helvetica,Ariel\" size=\"1\" color=\"#336699\">
		<input type=\"text\" size=\"15\" name=\"query\">
	      </font>
	    </td>
	  </tr>
	</table>
    </td>
    <td bgcolor=\"#ADD8E6\">
	 
    </td>
  </tr>
  <tr>
    <td colspan=\"3\" height=\"32\">
       
    </td>
  </tr>
</table>

</form>

<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">
  <tr>
    <td valign=\"top\" width=\"135\">
      <table>
        <tr>
          <td>
            <a href=\"",RelPath,"index.html\"><img src=\"",RelPath,"images/erlang.gif\" border=\"0\" alt=\"Home\"></a>
          </td>
        </tr>
        <tr>
          <td>
      <b>· <a href=\"",RelPath,"index.html\"><font face=\"Helvetica,Ariel\" size=-1>Home</font></a></b><br>
      <b>· <a href=\"",RelPath,"mirrors.html\"><font face=\"Helvetica,Ariel\" size=-1>Mirrors</font></a></b><br>
      <b>· <a href=\"",RelPath,"download.html\"><font face=\"Helvetica,Ariel\" size=-1>Download</font></a></b><br>
      <b>· <a href=\"",RelPath,"links.html\"><font face=\"Helvetica,Ariel\" size=-1>Links and Activities</font></a></b><br>
      <b>· <a href=\"",RelPath,"faq.html\"><font face=\"Helvetica,Ariel\" size=-1>FAQs + Contact</font></a></b><br>
      <b>· <a href=\"",RelPath,"starting.html\"><font face=\"Helvetica,Ariel\" size=-1>Getting started</font></a></b><br>
      <b>· <a href=\"",RelPath,"doc.html\"><font face=\"Helvetica,Ariel\" size=-1>Documentation</font></a></b><br>
      <b>· <a href=\"",RelPath,"examples.html\"><font face=\"Helvetica,Ariel\" size=-1>Examples</font></a></b><br>
      <b>· <a href=\"",RelPath,"user.html\"><font face=\"Helvetica,Ariel\" size=-1>User Contributions</font></a></b><br>
      <br>
      <br>
      <br>
      <i><font face=\"Helvetica,Ariel\" size=-2>For comments or questions about this site, contact
      <a href=\"mailto:\"></a></font></i>
          </td>
        </tr>
      </table>
    </td>
    <td valign=\"top\" width=\"29\" background=\"",RelPath,"images/vr.gif\">     </td>
    <td valign=\"top\">
"]
end
</def>

<def name="footer">
fun(_, Str) ->
{{Year, Month, Day},{Hour, Minute, Second}} = calendar:universal_time(),
Updated = io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w UTC\n",[Year, Month, Day, Hour, Minute]),
["
    </td>
  </tr>
  <tr>
    <td colspan=\"3\" height=\"34\">
       
    </td>
  </tr>
  <tr>
    <td colspan=\"3\" height=\"34\" align=\"center\" bgcolor=\"#ADD8E6\">
      Last updated   ",Updated,"
    </td>
  </tr>
</table>
"]
end
</def>


<def name="color">
fun(_,S) ->
	["<table width=\"100%\" bgcolor=\"#ADD8E6\" border=0 cellspacing=0
cellpadding=4><tr><td>\n",S,"</td></tr></table>\n"]
end
</def>

<def name="banner">
fun(_,Str) ->
	["<color><center><b>",Str,"</b></center></color><p>"]
end
</def>

<def name="box">
  fun(_, Str) ->
	  Entity =
	      fun($&) -> "&";
		 ($<) -> "<";
		 ($>) -> ">";
		 (C)  -> C
	      end,
["<table border=1 cellpadding=10>
  <tr>
    <td>
      <pre><b>
",lists:map(Entity,Str),"
      </b></pre>
    </td>
  </tr>
</table>"]
  end

</def>

<def name="lit">
  fun(_, Str) ->
	  Entity =
	      fun($&) -> "&";
		 ($<) -> "<";
		 ($>) -> ">";
		 (C)  -> C
	      end,
["<pre><b>
", lists:map(Entity,Str), "
</b></pre>"]
  end
</def>

<def name="indent">
fun(_, Str) ->
	["<blockquote>",Str,"</blockquote>"]
end
</def>

<def name="insert_file">
  fun(_, Str) ->
   	  {ok, Bin} = file:read_file(Str),
	  Entity =
	      fun($&) -> "&";
		 ($<) -> "<";
		 ($>) -> ">";
		 (C)  -> C
	      end,
["<pre>
",lists:map(Entity,binary_to_list(Bin)),"
</pre>"]
end
</def>


<!-- ############################################################ -->

<def name="yes">
fun(_, Str) ->
	X = "download/" ++ Str,
	Meg = case file:file_info(X) of
	  {ok, Tup} -> 
             I = element(1, Tup) div (100 * 1024),  % 1/10 meg
             K = element(1, Tup) div 1024,  % Kbytes
             if
                I == 0 -> "(" ++ integer_to_list(K) ++ " KB)";
                true ->  
                  case lists:reverse(integer_to_list(I)) of
                     [Last] -> "(0." ++ integer_to_list(I) ++ " MB)";
                     [Last|T] -> "(" ++ lists:reverse(T) ++ "." ++ 
                                 [Last] ++ " MB)";
                     _ -> ""
                  end
               end;
            _ ->
                "Broken link !!! "
         end,            
 Yes = "yes",
 ["<td><a href=\"download/",  Str,"\">",  Yes, "</a>", "  ", Meg, "</td>"]
end
</def>


<def name="download_file">
fun(_, String) ->
        X = "download/" ++ String,
	Meg = case file:file_info(X) of
	  {ok, Tup} -> 
             I = element(1, Tup) div (100 * 1024),  % 1/10 meg
             K = element(1, Tup) div 1024,  % Kbytes
             if
                I == 0 -> "(" ++ integer_to_list(K) ++ " KB)";
                true ->  
                  case lists:reverse(integer_to_list(I)) of
                     [Last] -> "(0." ++ integer_to_list(I) ++ " MB)";
                     [Last|T] -> "(" ++ lists:reverse(T) ++ "." ++ 
                                 [Last] ++ " MB)";
                     _ -> ""
                  end
               end;
            _ ->
                "Broken link !!! "
         end,      
	["<dt><a href=\"download/",
         String,"\">",  "<b>", String, "</b>", "</a>", "  ", Meg]


        end
</def>


<def name="no">
fun(_, Str) ->
	["<td>no</td>"]
end
</def>


<def name="soon">
fun(_, Str) ->
	["<td>soon</td>"]
end
</def>

<def name="na">
fun(_, Str) ->
	["<td> </td>"]
end
</def>

<def name="mirrors">
fun(_, Str) ->
    {ok,Binary} = file:read_file("MIRRORS"),
    Chars = binary_to_list(Binary),
    Lines = string:tokens(Chars, "\n"),
    Fun =
        fun(Line, Acc)
           ->
                case Line of
                    "URL:" ++ URL ->
                        Url = string:strip(URL),
                        Acc ++ "  <li><a href=\"" ++ Url ++ "\">" ++ Url ++ "</a>\n";
                    "TXT:" ++ TXT ->
                        Txt = string:strip(TXT),
                        Acc ++ "      (" ++ Txt ++ ")\n";
                    _ ->
                        Acc
                end
        end,
    lists:foldl(Fun, [], Lines)
end
</def>



More information about the erlang-questions mailing list