| 1 |
(* This CDuce script produces CDuce web site. *)
|
| 2 |
|
| 3 |
(** Output types **)
|
| 4 |
|
| 5 |
include "xhtml-strict.cd";; (* XHTML 1 Strict DTD *)
|
| 6 |
include "xhtml-categ.cd";; (* Categories (Inline, ...) from this DTD *)
|
| 7 |
|
| 8 |
|
| 9 |
(** Input types **)
|
| 10 |
|
| 11 |
type Page = <page name=String>[ <title>String <banner>[InlineText*] Item* ];;
|
| 12 |
type External = <external {|href=String; title=String; name=String |}>[];;
|
| 13 |
|
| 14 |
type Item =
|
| 15 |
<box title=String; subtitle=?String; link=String>Content
|
| 16 |
| <meta>Content
|
| 17 |
| <left>Content
|
| 18 |
| Page
|
| 19 |
| External;;
|
| 20 |
|
| 21 |
type Author = <author>String;;
|
| 22 |
type Paper =
|
| 23 |
<paper file=?String>[
|
| 24 |
<title>String Author+ <comment>[InlineText*] <abstract>Content ];;
|
| 25 |
|
| 26 |
type Slides =
|
| 27 |
<slides file=String>[ <title>String Author+ <comment>[InlineText*] ];;
|
| 28 |
|
| 29 |
type Link =
|
| 30 |
<link url=String; title=String>[ InlineText* ];;
|
| 31 |
|
| 32 |
type Content =
|
| 33 |
[ ( <p {||}>[InlineText*]
|
| 34 |
| <ul {||}>[<li {||}>Content +]
|
| 35 |
| <section title=String>Content
|
| 36 |
| <sample highlight=?"true"|"false">String
|
| 37 |
| Xtable
|
| 38 |
| Paper | Slides | Link
|
| 39 |
| <boxes-toc>[]
|
| 40 |
| <pages-toc>[]
|
| 41 |
| <site-toc>[]
|
| 42 |
| <local-links href=String>[]
|
| 43 |
| InlineText
|
| 44 |
)* ];;
|
| 45 |
|
| 46 |
type InlineText =
|
| 47 |
Char
|
| 48 |
| <(`b|`i|`tt|`em) {||}>[InlineText*]
|
| 49 |
| <code>String
|
| 50 |
| <local href=String>String
|
| 51 |
| Xa | Ximg | Xbr ;;
|
| 52 |
|
| 53 |
|
| 54 |
(** Generic purpose functions **)
|
| 55 |
|
| 56 |
(* Recursive inclusion of XML files and verbatim text files *)
|
| 57 |
|
| 58 |
let fun load_include (String -> [Any*])
|
| 59 |
name ->
|
| 60 |
let _ = print [ 'Loading ' !name '... \n' ] in
|
| 61 |
xtransform [ (load_xml name) ] with
|
| 62 |
| <include file=(s & String)>[] -> load_include s
|
| 63 |
| <include-verbatim file=(s & String)>[] -> load_file s;;
|
| 64 |
|
| 65 |
(* Highlighting text between {{...}} *)
|
| 66 |
|
| 67 |
let fun highlight (String -> [ (Char | Xvar)* ] )
|
| 68 |
| [ '{{' h ::(Char *?) '}}' ; rest ] ->
|
| 69 |
[ <var class="highlight">h; highlight rest ]
|
| 70 |
| [ c; rest ] -> [ c; highlight rest ]
|
| 71 |
| [] -> [];;
|
| 72 |
|
| 73 |
(* Split a comma-separated string *)
|
| 74 |
|
| 75 |
let fun split_comma (String -> [String*])
|
| 76 |
| [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest)
|
| 77 |
| s -> [ s ];;
|
| 78 |
|
| 79 |
|
| 80 |
(** Ugly hack to introduce PHP code ...
|
| 81 |
The idea is to produce first an XML document with a distinguished element.
|
| 82 |
The function patch_css search for the textual representation of this
|
| 83 |
element and replace it with the PHP code. **)
|
| 84 |
|
| 85 |
let php_css : String =
|
| 86 |
[' <?php
|
| 87 |
$browser = getenv("HTTP_USER_AGENT");
|
| 88 |
if (preg_match("/MSIE/i", "$browser")) {
|
| 89 |
$css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\"
|
| 90 |
type=\\"text/css\\">";
|
| 91 |
} elseif (preg_match("/Mozilla/i", "$browser")) {
|
| 92 |
$css = "<blink>For better presentation use a more recent version
|
| 93 |
of your browser, like Netscape 6</blink>";
|
| 94 |
} if (preg_match("/Mozilla\\/5.0/i", "$browser")) {
|
| 95 |
$css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\"
|
| 96 |
type=\\"text/css\\">";
|
| 97 |
} elseif (preg_match("/opera/i", "$browser")) {
|
| 98 |
$css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\"
|
| 99 |
type=\\"text/css\\">";
|
| 100 |
}
|
| 101 |
echo "$css";
|
| 102 |
?> '];;
|
| 103 |
|
| 104 |
|
| 105 |
let fun patch_css (String -> String)
|
| 106 |
| [ a::_*? '<meta content="css"/>'; rem ] -> a @ php_css @ rem
|
| 107 |
| s -> s;;
|
| 108 |
|
| 109 |
|
| 110 |
|
| 111 |
(** Internal types **)
|
| 112 |
|
| 113 |
type Path = [ { url = String; title = String }* ];;
|
| 114 |
type Tree = { name = String; url = String; title = String;
|
| 115 |
children = [Tree*] } ;;
|
| 116 |
|
| 117 |
let fun url_of_name (String -> String)
|
| 118 |
"index" -> "/"
|
| 119 |
| s -> s @ ".html";;
|
| 120 |
|
| 121 |
let fun authors ([Author+] -> String)
|
| 122 |
| [ <author>a ] -> a
|
| 123 |
| [ <author>a1 <author>a2 ] -> a1 @ ", and " @ a2
|
| 124 |
| [ <author>a; rem ] -> a @ ", " @ authors rem;;
|
| 125 |
|
| 126 |
let fun find_local_link (sitemap : [Tree*], l : String) : Tree =
|
| 127 |
match sitemap with
|
| 128 |
| (h,t) ->
|
| 129 |
if (h . name = l) then h
|
| 130 |
else
|
| 131 |
(try find_local_link (t,l) with `Not_found ->
|
| 132 |
find_local_link (h . children,l))
|
| 133 |
| [] -> raise `Not_found;;
|
| 134 |
|
| 135 |
let fun local_link (sitemap : Tree, l : String, txt : String) : Inline =
|
| 136 |
try
|
| 137 |
let h = find_local_link ([sitemap],l) in
|
| 138 |
let txt = if txt = "" then h . title else txt in
|
| 139 |
<a href=(h . url)>txt
|
| 140 |
with `Not_found -> raise [ 'Local link not found: ' !l ];;
|
| 141 |
|
| 142 |
let fun compute_sitemap ((Page|External) -> Tree)
|
| 143 |
<page name=name>[ <title>title (c::(Page|External) | _)* ] ->
|
| 144 |
let children = map c with p -> compute_sitemap p in
|
| 145 |
{ name = name; url = url_of_name name; title = title; children =children }
|
| 146 |
|<external name=name; href=h; title=t>[] ->
|
| 147 |
{ name = name; url = h; title = t; children = [] };;
|
| 148 |
|
| 149 |
let fun display_sitemap (h : Tree) : Xli =
|
| 150 |
let ch = map h . children with x -> display_sitemap x in
|
| 151 |
let ch = match ch with [] -> [] | l -> [ <ul>l ] in
|
| 152 |
<li>[ <a href=(h . url)>(h . title); ch ];;
|
| 153 |
|
| 154 |
(* Main transformation function *)
|
| 155 |
|
| 156 |
let fun gen_page (page : Page, path : Path, sitemap : Tree) : [] =
|
| 157 |
match page with
|
| 158 |
<page name=name>[ <title>title <banner>banner ; items ] ->
|
| 159 |
|
| 160 |
let fun text (t : [InlineText*]) : Inlines =
|
| 161 |
map t with
|
| 162 |
| <code>x -> <b>[ <tt>(highlight x) ]
|
| 163 |
| <local href=l>txt -> local_link (sitemap,l,txt)
|
| 164 |
| <(tag & (`b|`i|`tt|`em))>x -> <(tag)>(text x)
|
| 165 |
| z -> z
|
| 166 |
in
|
| 167 |
|
| 168 |
let fun content (t : Content) : Flow =
|
| 169 |
transform t with
|
| 170 |
| <section title=title>c ->
|
| 171 |
[ <h4>title !(content c) ]
|
| 172 |
| <paper (r)>[ <title>tit aut::Author* <comment>com <abstract>ab ] ->
|
| 173 |
[ (match r with { file = f } -> <a href=f>tit | _ -> <b>tit) '. '
|
| 174 |
!(authors aut) '. '
|
| 175 |
!(text com)
|
| 176 |
<div class="abstract">[ 'Abstract:' !(content ab) ]
|
| 177 |
]
|
| 178 |
| <slides file=f>[ <title>tit aut::Author* <comment>com ] ->
|
| 179 |
[ <a href=f>tit '. ' !(authors aut) '. ' !(text com) ]
|
| 180 |
| <sample highlight="false">s ->
|
| 181 |
[ <div class="code">[ <pre>s ] ]
|
| 182 |
| <sample>s ->
|
| 183 |
[ <div class="code">[ <pre>(highlight s) ] ]
|
| 184 |
| <link url=url; title=title>com ->
|
| 185 |
[ <a href=url>title '. ' !(text com) ]
|
| 186 |
| <ul>lis ->
|
| 187 |
[ <ul>(map lis with <li>x -> <li>(content x)) ]
|
| 188 |
| Xtable & x ->
|
| 189 |
[ x ]
|
| 190 |
| <p>x -> [ <p>(text x) ]
|
| 191 |
| <pages-toc>[] ->
|
| 192 |
let toc =
|
| 193 |
transform items with
|
| 194 |
| <page name=l>[<title>t;_] -> [ <li>[ <a href=(url_of_name l)>t ] ]
|
| 195 |
| <external href=l; title=t>[] -> [ <li>[ <a href=l>t ] ] in
|
| 196 |
(match toc with [] -> [] | lis -> [ <ul>lis ])
|
| 197 |
| <boxes-toc>[] ->
|
| 198 |
let toc =
|
| 199 |
transform items with
|
| 200 |
<box title=t; link=l>_ -> [ <li>[ <a href=('#',l)>t ] ] in
|
| 201 |
(match toc with [] -> [] | lis -> [ <ul>lis ])
|
| 202 |
| <site-toc>[] ->
|
| 203 |
[ <ul>[ (display_sitemap sitemap) ] ]
|
| 204 |
| <local-links href=s>[] ->
|
| 205 |
(match (split_comma s) with
|
| 206 |
| [] -> []
|
| 207 |
| l -> let l = map l with x -> <li>[ (local_link(sitemap,x,"")) ]
|
| 208 |
in [ <ul>l ])
|
| 209 |
| t -> text [ t ]
|
| 210 |
in
|
| 211 |
|
| 212 |
let main : Flow = transform items with
|
| 213 |
| <box (r)>c ->
|
| 214 |
[ <div class="box">[
|
| 215 |
<h2>(r . title)
|
| 216 |
!(match r with { subtitle = t } -> [<b>t] | _ -> [])
|
| 217 |
<a name=r . link>[]
|
| 218 |
!(content c) ] ]
|
| 219 |
| <meta>c -> [ <div class="meta">(content c) ]
|
| 220 |
in
|
| 221 |
let navig : Flow = transform items with
|
| 222 |
| <left>c -> [<div class="box">(content c)]
|
| 223 |
in
|
| 224 |
let dpath : Inlines = transform path with
|
| 225 |
| { url = f; title = t } -> [ <a href=f>t ' :: ']
|
| 226 |
in
|
| 227 |
let html : Xhtml =
|
| 228 |
<html>[
|
| 229 |
<head>[
|
| 230 |
<title>title
|
| 231 |
<meta content="text/html; charset=iso-8859-1"; http-equiv="Content-Type">[]
|
| 232 |
<meta content="css">[] (* Placeholder for PHP code *)
|
| 233 |
]
|
| 234 |
<body>[
|
| 235 |
<div class="title">[ <h1>(text banner) <p>[ !dpath !title ] ]
|
| 236 |
<div id="Sidelog">navig
|
| 237 |
<div id="Content">main
|
| 238 |
]
|
| 239 |
]
|
| 240 |
in
|
| 241 |
let txt : String =
|
| 242 |
[ (* '<?xml version="1.0" encoding="iso-8859-1"?>' *)
|
| 243 |
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
|
| 244 |
' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
| 245 |
!(patch_css (print_xml html)) ] in
|
| 246 |
let [] = dump_to_file (name @ ".html.php") txt in
|
| 247 |
let url = url_of_name name in
|
| 248 |
let path = path @ [ { url = url; title = title } ] in
|
| 249 |
transform items with p & Page -> gen_page (p,path,sitemap);;
|
| 250 |
|
| 251 |
|
| 252 |
(* Entry point *)
|
| 253 |
|
| 254 |
match load_include "site.xml" with
|
| 255 |
| [ Page & p ] -> gen_page (p,[], compute_sitemap p)
|
| 256 |
| _ -> raise "Invalid site.xml";;
|
| 257 |
|