(* This CDuce script produces CDuce web site. *) (** Output types **) include "xhtml-strict.cd";; (* XHTML 1 Strict DTD *) include "xhtml-categ.cd";; (* Categories (Inline, ...) from this DTD *) (** Input types **) type Page = [ String <banner>[InlineText*] Item* ];; type External = <external {|href=String; title=String; name=String |}>[];; type Item = <box title=String; subtitle=?String; link=String>Content | <meta>Content | <left>Content | Page | External;; type Author = <author>String;; type Paper = <paper file=?String>[ <title>String Author+ <comment>[InlineText*] <abstract>Content ];; type Slides = <slides file=String>[ <title>String Author+ <comment>[InlineText*] ];; type Link = <link url=String; title=String>[ InlineText* ];; type Content = [ ( <p {||}>[InlineText*] | <ul {||}>[<li {||}>Content +] | <section title=String>Content | <sample highlight=?"true"|"false">String | Xtable | Paper | Slides | Link | <boxes-toc>[] | <pages-toc>[] | <site-toc>[] | <local-links href=String>[] | InlineText )* ];; type InlineText = Char | <(`b|`i|`tt|`em) {||}>[InlineText*] | <code>String | <local href=String>String | Xa | Ximg | Xbr ;; (** Generic purpose functions **) (* Recursive inclusion of XML files and verbatim text files *) let fun load_include (String -> [Any*]) name -> let _ = print [ 'Loading ' !name '... \n' ] in xtransform [ (load_xml name) ] with | <include file=(s & String)>[] -> load_include s | <include-verbatim file=(s & String)>[] -> load_file s;; (* Highlighting text between {{...}} *) let fun highlight (String -> [ (Char | Xvar)* ] ) | [ '{{' h ::(Char *?) '}}' ; rest ] -> [ <var class="highlight">h; highlight rest ] | [ c; rest ] -> [ c; highlight rest ] | [] -> [];; (* Split a comma-separated string *) let fun split_comma (String -> [String*]) | [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest) | s -> [ s ];; (** Ugly hack to introduce PHP code ... The idea is to produce first an XML document with a distinguished element. The function patch_css search for the textual representation of this element and replace it with the PHP code. **) let php_css : String = [' <?php $browser = getenv("HTTP_USER_AGENT"); if (preg_match("/MSIE/i", "$browser")) { $css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\" type=\\"text/css\\">"; } elseif (preg_match("/Mozilla/i", "$browser")) { $css = "<blink>For better presentation use a more recent version of your browser, like Netscape 6</blink>"; } if (preg_match("/Mozilla\\/5.0/i", "$browser")) { $css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\" type=\\"text/css\\">"; } elseif (preg_match("/opera/i", "$browser")) { $css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\" type=\\"text/css\\">"; } echo "$css"; ?> '];; let fun patch_css (String -> String) | [ a::_*? '<meta content="css"/>'; rem ] -> a @ php_css @ rem | s -> s;; (** Internal types **) type Path = [ { url = String; title = String }* ];; type Tree = { name = String; url = String; title = String; children = [Tree*] } ;; let fun url_of_name (String -> String) "index" -> "/" | s -> s @ ".html";; let fun authors ([Author+] -> String) | [ <author>a ] -> a | [ <author>a1 <author>a2 ] -> a1 @ ", and " @ a2 | [ <author>a; rem ] -> a @ ", " @ authors rem;; let fun find_local_link (sitemap : [Tree*], l : String) : Tree = match sitemap with | (h,t) -> if (h . name = l) then h else (try find_local_link (t,l) with `Not_found -> find_local_link (h . children,l)) | [] -> raise `Not_found;; let fun local_link (sitemap : Tree, l : String, txt : String) : Inline = try let h = find_local_link ([sitemap],l) in let txt = if txt = "" then h . title else txt in <a href=(h . url)>txt with `Not_found -> raise [ 'Local link not found: ' !l ];; let fun compute_sitemap ((Page|External) -> Tree) <page name=name>[ <title>title (c::(Page|External) | _)* ] -> let children = map c with p -> compute_sitemap p in { name = name; url = url_of_name name; title = title; children =children } |<external name=name; href=h; title=t>[] -> { name = name; url = h; title = t; children = [] };; let fun display_sitemap (h : Tree) : Xli = let ch = map h . children with x -> display_sitemap x in let ch = match ch with [] -> [] | l -> [ <ul>l ] in <li>[ <a href=(h . url)>(h . title); ch ];; (* Main transformation function *) let fun gen_page (page : Page, path : Path, sitemap : Tree) : [] = match page with <page name=name>[ <title>title <banner>banner ; items ] -> let fun text (t : [InlineText*]) : Inlines = map t with | <code>x -> <b>[ <tt>(highlight x) ] | <local href=l>txt -> local_link (sitemap,l,txt) | <(tag & (`b|`i|`tt|`em))>x -> <(tag)>(text x) | <a href=url>_ & z -> let [] = print [ 'External link: ' !url '\n'] in z | z -> z in let fun content (t : Content) : Flow = transform t with | <section title=title>c -> [ <h4>title !(content c) ] | <paper (r)>[ <title>tit aut::Author* <comment>com <abstract>ab ] -> [ (match r with { file = f } -> <a href=f>tit | _ -> <b>tit) '. ' !(authors aut) '. ' !(text com) <div class="abstract">[ 'Abstract:' !(content ab) ] ] | <slides file=f>[ <title>tit aut::Author* <comment>com ] -> [ <a href=f>tit '. ' !(authors aut) '. ' !(text com) ] | <sample highlight="false">s -> [ <div class="code">[ <pre>s ] ] | <sample>s -> [ <div class="code">[ <pre>(highlight s) ] ] | <link url=url; title=title>com -> [ <a href=url>title '. ' !(text com) ] | <ul>lis -> [ <ul>(map lis with <li>x -> <li>(content x)) ] | Xtable & x -> [ x ] | <p>x -> [ <p>(text x) ] | <pages-toc>[] -> let toc = transform items with | <page name=l>[<title>t;_] -> [ <li>[ <a href=(url_of_name l)>t ] ] | <external href=l; title=t>[] -> [ <li>[ <a href=l>t ] ] in (match toc with [] -> [] | lis -> [ <ul>lis ]) | <boxes-toc>[] -> let toc = transform items with <box title=t; link=l>_ -> [ <li>[ <a href=('#',l)>t ] ] in (match toc with [] -> [] | lis -> [ <ul>lis ]) | <site-toc>[] -> [ <ul>[ (display_sitemap sitemap) ] ] | <local-links href=s>[] -> (match (split_comma s) with | [] -> [] | l -> let l = map l with x -> <li>[ (local_link(sitemap,x,"")) ] in [ <ul>l ]) | t -> text [ t ] in let main : Flow = transform items with | <box (r)>c -> [ <div class="box">[ <h2>(r . title) !(match r with { subtitle = t } -> [<b>t] | _ -> []) <a name=r . link>[] !(content c) ] ] | <meta>c -> [ <div class="meta">(content c) ] in let navig : Flow = transform items with | <left>c -> [<div class="box">(content c)] in let dpath : Inlines = transform path with | { url = f; title = t } -> [ <a href=f>t ' :: '] in let html : Xhtml = <html>[ <head>[ <title>[ 'CDuce: ' !title ] <meta content="text/html; charset=iso-8859-1"; http-equiv="Content-Type">[] <meta content="css">[] (* Placeholder for PHP code *) ] <body>[ <div class="title">[ <h1>(text banner) <p>[ <b>"You're here: " !dpath !title ] ] <div id="Sidelog">navig <div id="Content">main ] ] in let txt : String = [ (* '<?xml version="1.0" encoding="iso-8859-1"?>' *) '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' !(patch_css (print_xml html)) ] in let [] = dump_to_file (name @ ".html.php") txt in let url = url_of_name name in let path = path @ [ { url = url; title = title } ] in transform items with p & Page -> gen_page (p,path,sitemap);; (* Entry point *) match load_include "site.xml" with | [ Page & p ] -> gen_page (p,[], compute_sitemap p) | _ -> raise "Invalid site.xml";;