Commit 80454c16 authored by Pietro Abate's avatar Pietro Abate
Browse files

- fix xtransform.cd for the cgi evaluator

- add required files to build the documentation
parent 2e902f1f
...@@ -34,11 +34,10 @@ debug: ...@@ -34,11 +34,10 @@ debug:
# Packaging # Packaging
DISTRIB = $(DIRS) cduce.spec tools depend INSTALL INSTALL.WIN32 CHANGES \ DISTRIB = $(DIRS) web cduce.spec tools depend INSTALL INSTALL.WIN32 CHANGES \
LICENSE README AUTHORS Makefile.conf.template configure configure.ml doc \ LICENSE README AUTHORS Makefile.conf.template configure configure.ml doc \
META.in cduce_mktop VERSION PLIST.godi META.in cduce_mktop VERSION PLIST.godi
# currently not used. Documentation online.
DISTRIB_DOC = doc.xml memento.xml tutorial.xml manual.xml tutorial manual \ DISTRIB_DOC = doc.xml memento.xml tutorial.xml manual.xml tutorial manual \
xhtml.cd xhtml-categ.cd xhtml-strict.cd site.cd siteTypes.cd xhtml.cd xhtml-categ.cd xhtml-strict.cd site.cd siteTypes.cd
......
...@@ -1300,8 +1300,7 @@ let bib : Biblio = ...@@ -1300,8 +1300,7 @@ let bib : Biblio =
let titles = [bib]/<paper>_/<title>_ let titles = [bib]/<paper>_/<title>_
let authors = [bib]/<paper>_/<author>_ let authors = [bib]/<paper>_/<author>_
let titles_concat = [bib]/<paper>_/<title>_/Char let titles_concat = [bib]/<paper>_/<title>_/Char
";"xtransform"," ";"xtransform","(* For the purpose of the example we can consider this hugely
(* For the purpose of the example we can consider this hugely
simplified definition of Xhtml simplified definition of Xhtml
*) *)
...@@ -1327,7 +1326,7 @@ type Address = <address>[ Inline* ];; ...@@ -1327,7 +1326,7 @@ type Address = <address>[ Inline* ];;
type Pre = <pre>[ (PCDATA | A | Fontstyle)* ];; type Pre = <pre>[ (PCDATA | A | Fontstyle)* ];;
type Center = <center>[ Block* ];; type Center = <center>[ Block* ];;
type A = <a ({ name = String } | { href = String })>[ (Inline \ A)* ];; type A = <a ({ name = String } | { href = String })>[ (Inline)* ];;
type Tt = <tt>[ Inline* ];; type Tt = <tt>[ Inline* ];;
type I = <i>[ Inline* ];; type I = <i>[ Inline* ];;
type B = <b>[ Inline* ];; type B = <b>[ Inline* ];;
...@@ -1343,7 +1342,7 @@ type Small = <small>[ Inline* ];; ...@@ -1343,7 +1342,7 @@ type Small = <small>[ Inline* ];;
document as follows document as follows
*) *)
let bold(x:[Xhtml]):[Xhtml]=xtransform x with <a (y)>t -> [ <a(y)>[<b>t] ] let bold (x:[Xhtml]):[Xhtml] = xtransform x with <a (y)>t -> [ <a (y)>[<b>t] ]
(* let us apply the function to a document where links appear (* let us apply the function to a document where links appear
...@@ -1372,7 +1371,7 @@ let doc : Xhtml = ...@@ -1372,7 +1371,7 @@ let doc : Xhtml =
<a href=\"xtransform\">[<tt>\"xtransform\"] <a href=\"xtransform\">[<tt>\"xtransform\"]
' will put all links in bold so that when' ' will put all links in bold so that when'
' you program your transformation you ' ' you program your transformation you '
<big>[<a name=\"\">\" don\'t \" ] ' have to worry about it' <big>[<a name=\"\">\" don't \" ] ' have to worry about it'
] ]
] ]
];; ];;
......
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<site>
<title>CDuce</title>
<footer>
<meta>
<p>
<local href="sitemap">Site map</local>
</p>
</meta>
</footer>
<page name="index">
<title>CDuce: documentation</title>
<include file="tutorial.xml"/>
<include file="manual.xml"/>
<include file="memento.xml"/>
<left>
<p>
This is the main entry point to CDuce documentation.
</p>
<pages-toc/>
</left>
<box title="Available documents" link="src">
<p>
We mantain three kinds of on-line documentation: a <a
href="manual.html">User's guide</a> where all CDuce constructions are
grouped by categories and explained; a <a href="tutorial.html">Tutorial</a>
where we give a gentle introduction to programming in CDuce; and a
<a href="memento.html">Quick reference card</a> where we group and briefly explain in a single page CDuce syntax.
</p>
</box>
<page name="sitemap">
<title>Sitemap</title>
<left>
<p>This page lists all the pages from the CDuce documentation.</p>
</left>
<box title="Sitemap" link="sitemap">
<site-toc/>
</box>
</page>
</page>
</site>
(* For the purpose of the example we can consider this hugely (* For the purpose of the example we can consider this hugely
simplified definition of Xhtml simplified definition of Xhtml
*) *)
...@@ -25,7 +24,7 @@ type Address = <address>[ Inline* ];; ...@@ -25,7 +24,7 @@ type Address = <address>[ Inline* ];;
type Pre = <pre>[ (PCDATA | A | Fontstyle)* ];; type Pre = <pre>[ (PCDATA | A | Fontstyle)* ];;
type Center = <center>[ Block* ];; type Center = <center>[ Block* ];;
type A = <a ({ name = String } | { href = String })>[ (Inline \ A)* ];; type A = <a ({ name = String } | { href = String })>[ (Inline)* ];;
type Tt = <tt>[ Inline* ];; type Tt = <tt>[ Inline* ];;
type I = <i>[ Inline* ];; type I = <i>[ Inline* ];;
type B = <b>[ Inline* ];; type B = <b>[ Inline* ];;
...@@ -41,7 +40,7 @@ type Small = <small>[ Inline* ];; ...@@ -41,7 +40,7 @@ type Small = <small>[ Inline* ];;
document as follows document as follows
*) *)
let bold(x:[Xhtml]):[Xhtml]=xtransform x with <a (y)>t -> [ <a(y)>[<b>t] ] let bold (x:[Xhtml]):[Xhtml] = xtransform x with <a (y)>t -> [ <a (y)>[<b>t] ]
(* let us apply the function to a document where links appear (* let us apply the function to a document where links appear
...@@ -70,7 +69,7 @@ let doc : Xhtml = ...@@ -70,7 +69,7 @@ let doc : Xhtml =
<a href="xtransform">[<tt>"xtransform"] <a href="xtransform">[<tt>"xtransform"]
' will put all links in bold so that when' ' will put all links in bold so that when'
' you program your transformation you ' ' you program your transformation you '
<big>[<a name="">" don\'t " ] ' have to worry about it' <big>[<a name="">" don't " ] ' have to worry about it'
] ]
] ]
];; ];;
......
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<page name="manual">
<title>User's manual</title>
<include file="manual/interpreter.xml"/>
<include file="manual/types_patterns.xml"/>
<include file="manual/expressions.xml"/>
<include file="manual/namespaces.xml"/>
<include file="manual/schema.xml"/>
<include file="manual/schema_samples.xml"/>
<include file="manual/interface.xml"/>
<left>
<p>
This Guide describes all CDuce's constructions.
</p>
<pages-toc/>
<p>See also:</p>
<local-links href="index,tutorial,memento"/>
</left>
<box title="Table of Contents" link="toc">
<p>Sections:</p>
<pages-toc sections=""/>
</box>
</page>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<page name="memento">
<title>Quick reference</title>
<left>
<p>This page briefly presents the syntax of the CDuce language.</p>
<boxes-toc/>
<p>See also:</p>
<local-links href="index,manual,tutorial"/>
</left>
<box title="Identifiers" link="id">
<ul>
<li> Type and Pattern identifiers: words formed by of Unicode letters and
the underscore "_" character, starting by an uppercase letter. </li>
<li> value identifiers: words formed by of Unicode letters and the underscore "
_" character, starting by a lowercase letter or underscore.</li>
</ul>
</box>
<box title="Scalars" link="scalars">
<ul>
<li>Large integers:
<ul>
<li>Values: <code>0,1,2,3,...</code> </li>
<li>Types: intervals <code>-*--10, 20--30, 50--*, ...</code>,
singletons <code>0,1,2,3,...</code> </li>
<li>Operators: <code>+,-,/,*,div,mod, int_of</code> </li>
</ul>
</li>
<li>Floats:
<ul>
<li>Values: <i>none built-in</i>. </li>
<li>Types: only <code>Float</code>. </li>
<li>Operators: <code>float_of</code> : String -> Float</li>
</ul>
</li>
<li>Unicode characters:
<ul>
<li>Values: quoted characters (<code>'a'</code>, <code>'b'</code>,
<code>'c'</code>, ...,<code>'あ'</code>, <code>'い'</code>, ... ,
<code>'私'</code>, ... , <code>'⊆'</code>, ...),
codepoint-defined characters (<code>'\x%%h%%;' '\%%d%%;'
</code> where <code>%%h%%</code> and
<code>%%d%%</code> are hexadecimal and decimal integers
respectively), and backslash-escaped characters
(<code>'\t'</code> tab, <code>'\n'</code> newline,
<code>'\r'</code> return, <code>'\\'</code> backslash).</li>
<li>Types: intervals <code>'a'--'z', '0'--'9'</code>,
singletons <code>'a','b','c',...</code> </li>
<li>Operators: <code>char_of_int</code> : Int -> Char, <code>int_of_char</code> : Char -> Int</li>
</ul>
</li>
<li>Symbolic atoms:
<ul>
<li>Values: <code>`A, `B, `a, `b, `true, `false, ...</code> </li>
<li>Types: singletons <code>`A, `B, ...</code> </li>
<li>Operators: <code>make_atom</code> : (String,String) -> Atom,
<code>split_atom</code> : Atom -> (String,String) </li>
<li>CDuce also supports <local href="namespaces">XML Namespaces</local></li>
</ul>
</li>
</ul>
</box>
<box title="Operators, built-in functions" link="op">
<ul>
<li>Infix:
<br/> <code>@</code> : concatenation of sequences
<br/> <code>+,*,-,div,mod</code> : Integer,Integer -> Integer
<br/> <code>=, &lt;&lt;, &lt;=, &gt;&gt;, &gt;= </code> :
<i>t</i>,<i>t</i> -> Bool = <code>`true | `false</code> (any non functional type <i>t</i>)
<br/> <code>||, &amp;&amp;</code> : Bool,Bool -> Bool
<br/> <code>not</code>: Bool -> Bool
</li>
<li>Prefix:
<br/><code>load_xml</code> : Latin1 -> AnyXml,
<br/><code>load_html</code> : Latin1 -> [ Any* ],
<br/><code>load_file</code> : Latin1 -> Latin1,
<br/><code>load_file_utf8</code> : Latin1 -> String,
<br/><code>dump_to_file</code> : Latin1 -> String -> [],
<br/><code>dump_to_file_utf8</code> : Latin1 -> String -> [],
<br/><code>print_xml</code> : Any -> Latin1,
<br/><code>print_xml_utf8</code> : Any -> String,
<br/><code>print</code> : Latin1 -> [],
<br/><code>print_utf8</code> : String -> [],
<br/><code>dump_xml</code> : Any -> [],
<br/><code>dump_xml_utf8</code> : Any -> [],
<br/><code>int_of</code> : String -> Int,
<br/><code>float_of</code> : String -> Float,
<br/><code>string_of</code> : Any -> Latin1,
<br/><code>char_of_int</code> : Int -> Char,
<br/><code>make_atom</code> : (String,String) -> Atom,
<br/><code>split_atom</code> : Atom -> (String,String),
<br/><code>system</code> : Latin1 -> { stdout = Latin1; stderr = Latin1;
status = (`exited,Int) | (`stopped,Int) | (`signaled,Int)
},
<br/><code>exit</code> : 0--255 -> Empty,
<br/><code>getenv</code> : Latin1 -> Latin1,
<br/><code>argv</code> : [] -> [ String* ],
<br/><code>raise</code> : Any -> Empty
</li>
</ul>
</box>
<box title="Pairs" link="pair">
<ul>
<li>Expressions: <code>(e1,e2)</code> </li>
<li>Types and patterns: <code>(t1,t2)</code> </li>
<li>Note: tuples are right-associative pairs; e.g.:
<code>(1,2,3)=(1,(2,3))</code> </li>
<li>When a capture variable appears on both side of a pair pattern,
the two captured values are paired
together (e.g. <code>match (1,2,3) with (x,(_,x)) -> x ==>
(1,3)</code>). </li>
</ul>
</box>
<box title="Sequences" link="seq">
<ul>
<li>Expressions: <code>[ 1 2 3 ]</code>,
which is syntactic sugar for <code>(1,(2,(3,`nil)))</code> </li>
<li>A sub-sequence can be escaped by !: <code>[ 1 2 ![ 3 4 ] 5
]</code> is then equal to <code>[ 1 2 3 4 5 ]</code> . </li>
<li>Types and patterns : <code>[ R ]</code> where <code>R</code> is
a regular expression built on types and patterns:
<ul>
<li>A type or a pattern is a regexp by itself, matching a single
element of the sequence </li>
<li>Postfix repetition operators: <code>*,+,?</code>
and the ungreedy variants (for patterns) <code>*?, +?
,??</code></li>
<li>Concatenation of regexps</li>
<li>For patterns, sequence capture variable <code>x::R</code> </li>
</ul>
</li>
<li>It is possible to specify a tail, for expressions, types, and patterns;
e.g.: <code>[ x::Int*; q ]</code> </li>
<li>Map: <code>map e with p1 -> e1 | ... | pn -> en</code>.
Each element of e must be matched. </li>
<li>Transform: <code>transform e with p1 -> e1 | ... | pn -> en</code>.
Unmatched elements are discarded; each branch returns a sequence
and all the resulting sequences are concatenated together. </li>
<li>Selection: : <code>select %%e%% from %%p1%% in %%e1%% ... %%pn%%
in %%en%% where %%e'%%</code>. SQL-like selection with the possibility
of using CDuce patterns instead of variables. <code>%%e1%% ...
%%en%%</code> must be sequences and <code>%%e'%%</code> a boolean
expression.</li>
<li>Operators: concatenation <code>e1 @ e2 = [ !e1 !e2 ]</code>,
flattening <code>flatten e = transform e with x -> x</code>.
</li>
</ul>
</box>
<box title="Record" link="record">
<ul>
<li>Records literal <code>{ l1 = e1; ...; ln = en }</code></li>
<li>Types: <code>{ l1 = t1; ...; ln = tn }</code> (closed, no more
fields allowed), <code>{ l1 = t1; ...; ln = tn; .. }</code> (open,
any other field allowed). Optional fields: <code>li =? ti</code>
instead of <code>li = ti</code>. Semi-colons are optional.</li>
<li>Record concatenation: <code>e1 + e2</code>
(priority to the fields from the right argument) </li>
<li>Field removal: <code>e1 \ l</code> (does nothing if the
field <code>l</code> is not present)</li>
<li>Field access: <code>e1.l</code></li>
<li>Labels are in fact Qualified Names (see <local href="namespaces"/>)</li>
</ul>
</box>
<box title="Strings" link="string">
<ul>
<li>Strings are actually sequences of characters.</li>
<li>Expressions: <code>"abc", [ 'abc' ], [ 'a' 'b' 'c' ]</code>. </li>
<li>Operators: <code>string_of, print, dump_to_file</code></li>
<li><code>PCDATA</code> means <code>Char*</code> inside regular expressions</li>
</ul>
</box>
<box title="XML elements" link="xml">
<ul>
<li>Expressions: <code> &lt;(tag) (attr)>content</code> </li>
<li>If the tag is an atom <code>`X</code>, it can be written
<code>X</code> (without the <code>(..)</code>).
Similarly, parenthesis and curly braces may be omitted
when attr is a record <code>l1=e1;...;ln=en</code>
(semicolon can also be omitted in this case).
E.g: <code>&lt;a href="abc">[ 'abc' ]</code>.</li>
<li>Types and patterns: same notations.</li>
<li>XPath like projection: <code>%%e%%/%%t%%</code>. For every
XML tree in <code>%%e%%</code> it returns the sequence of children
of type <code>%%t%%</code></li>
<li>Tree transformation: <code>xtransform e with p1 -> e1 | ... | pn -> en</code>.
Applies to sequences of XML trees. Unmatched elements are left unchanged and the
transformation is recursively applied to the sequence of children of the unmatched
element; as for transform, each branch returns a sequence
and all the resulting sequences are concatenated together. </li>
<li>Operators: <code>load_xml : Latin1 -> AnyXml; print_xml : Any ->
Latin1; dump_xml : Any -> []</code>
</li>
</ul>
</box>
<box title="Functions" link="fun">
<ul>
<li>Expressions:
<ul>
<li>General form: <code>fun f (t1->s1;...;tn->sn)
p1 -> e1 | ... | pm -> em</code> (<code>f</code> is optional) </li>
<li>Simple function: <code>fun f (p : t) : s = e</code>,
equivalent to <code>fun f (t -> s) p -> e</code> </li>
<li>Multiple arguments: <code>fun f (p1 : t1, p2 : t2,...) : s =
e</code>, equivalent to <code>fun f ((p1,p2,...):(t1,t2,...)) : s
= e</code> (note the blank spaces around colons to avoid ambiguity
with namespaces) </li>
<li>Currified function: <code>fun f (p1 : t1) (p2 : t2) ... : s =
e</code> (can be combined with the multiple arguments syntax).</li>
</ul>
</li>
<li>Types: <code>t -> s</code> </li>
</ul>
</box>
<box title="Pattern matching, exceptions, ..." link="match">
<ul>
<li>Type restriction: <code>(e : t)</code> (forgets any more precise
type for <code>e</code>; note the blank spaces around colons to avoid ambiguity with namespaces) </li>
<li>Pattern matching: <code>match e with p1 -> e1 | ... | pn ->
en</code></li>
<li>Local binding: <code>let p = e1 in e2</code>, equivalent to
<code>match e1 with p -> e2</code>;
<code>let p : t = e1 in e2</code> equivalent to
<code>let p = (e1 : t) in e2</code> </li>
<li>If-then-else: <code>if e1 then e2 else e3</code>, equivalent to
<code>match e1 with `true -> e2 | `false -> e3</code></li>
<li>Exceptions: <ul>
<li>Raise exception: <code>raise e</code></li>
<li>Handle exception: <code>try e with p1 -> e1 | ... | pn ->
en</code></li>
</ul> </li>
</ul>
</box>
<box title="More about types and patterns" link="type">
<ul>
<li>Boolean connectives: <code>&amp;,|,\</code> (<code>|</code> is
first-match). </li>
<li>Empty and universal types: <code>Empty,Any</code> or
<code>_</code>.</li>
<li>Recursive types and patterns: <code>t where T1 = t2 and ... and
Tn = tn</code>.</li>
<li>Capture variable: <code>x</code>. </li>
<li>Default values: <code>(x := c)</code>. </li>
</ul>
</box>
<box title="References" link="ref">
<ul>
<li>Type: <code>ref %%T%%</code>.</li>
<li>Construction: <code>ref %%T%% %%e%%</code>.</li>
<li>Dereferencing: <code>!%%e1%%</code>.</li>
<li>Assignment: <code>%%e1%% := %%e2%%</code>.</li>
</ul>
</box>
<box title="Toplevel statements" link="toplevel">
<ul>
<li>Global expression to evaluate.</li>
<li>Global let-binding.</li>
<li>Global function declaration.</li>
<li>Type declarations: <code>type T = t</code>.</li>
<li>Global <local href="namespaces">namespace</local>:
<code>namespace p = "..."</code>,
<code>namespace "..."</code>.</li>
<li>Source inclusion: <code>include %%filename_string%%</code>.</li>
<li>Debug directives: <code>debug %%directive argument%%</code> <br/>
where <code>%%directive%%</code> is one of the following: <code>accept</code>,
<code>subtype</code>, <code>compile</code>, <code>sample</code>, <code>filter</code>.
</li>
<li>Toplevel directives: <code>#env</code>, <code>#quit</code>,
<code>#reinit_ns</code>.</li>
</ul>
</box>
</page>
(* This CDuce script produces CDuce web site. *)
(* The types *)
include "siteTypes.cd";;
(** Command line **)
let (input,outdir) =
match argv [] with
| [ s ("-o" o | /(o := "www")) ] -> (s,o)
| _ -> raise "Please use --arg to specify an input file on the command line"
(** Generic purpose functions **)
(* Recursive inclusion of XML files and verbatim text files *)
let load_include (Latin1 -> [Any*])
name ->
(* let _ = print [ 'Loading ' !name '... \n' ] in *)
xtransform [ (load_xml name) ] with
| <include file=(s & Latin1)>[] -> load_include s
| <include-verbatim file=(s & Latin1)>[] -> load_file s
| <include-forest file=(s & Latin1)>[] ->
match load_xml ("string:<fake>"@(load_file s)@"</fake>") with
<fake> x -> x | _ -> raise "Uhh?"
(* Loading *)
let [<site>[ <title>site
(<header>header | /(header:=[]))
(<footer>footer | /(footer:=[]))
extra_head::H.script*
main_page ] ] =
(* match load_include input with
[ Site ] & x -> x
| _ -> exit 2 *)
try (load_include input :? [ Site ])
with err & Latin1 ->
print ['Invalid input document:\n' !err '\n'];
exit 2
(* Highlighting text between {{...}} *)
let highlight (String -> [ (Char | H.strong | H.i)* ] )
| [ '{{ON}}'; rest ] -> xhighlight rest
| [ '{{%%' h ::(Char *?) '%%}}' ; rest ] ->
[ <strong class="highlight">[<i>h]; highlight rest ]
| [ '{{' h ::(Char *?) '}}' ; rest ] ->
[ <strong class="highlight">h; highlight rest ]
| [ '$$%%' h ::(Char *?) '%%$$' ; rest ] ->
[ <strong class="ocaml">[<i>h]; highlight rest ]
| [ '$$' h ::(Char *?) '$$' ; rest ] ->
[ <strong class="ocaml">h; highlight rest ]
| [ '%%' h ::(Char *?) '%%' ; rest ] ->
[ <i>h; highlight rest ]
| [ c; rest ] -> [ c; highlight rest ]
| [] -> []
let xhighlight (String -> [ (Char | H.strong | H.i)* ] )
| [ x::('}}' | ':}' | '{{' | '{:') h::Char*?
y::('}}' | ':}' | '{:' | '{{'); rest ] ->
[ !x <strong class="highlight">h !y; xhighlight rest ]
| [ c; rest ] -> [ c; xhighlight rest ]
| [] -> []
(* Split a comma-separated string *)
let split_comma (String -> [String*])
| [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest)
| s -> [ s ]
type wschar = ' ' | '\n' | '\t' | '\r'
let split_thumbnails (String -> [(String,String)*])
| [ wschar* x::(Char\wschar\':')+ ':' y::_*? '.'; rest ] ->
((x,y), split_thumbnails rest)
| [ wschar* x::(Char\wschar)+; rest ] ->
((x,""), split_thumbnails rest)
| [ wschar* ] -> []
(** Internal types **)
type Path = [ { url=String title=String }* ]
type Tree = { name=String url=String title=String
children=[Tree*] boxes=[H.ul?] }
let url_of_page (Page -> String)
| <page url=u ..>_ -> u
| <page name=n ..>_ -> n @ ".html"
let render(a : String)(p : {presenter=?"yes"|"no" ..}) : H.Flow =
match p with
| {presenter="yes" ..} -> [<strong class="ocaml">a]
| _ -> a
let authors ([Author+] -> H.Flow)
| [ <author (p)>a ] -> render a p
| [ <author (p1)>a1 <author (p2)>a2 ] ->
(render a1 p1) @ ", and " @ (render a2 p2)
| [ <author (p)>a; rem ] -> (render a p)@ ", " @ authors rem
let 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 local_link (sitemap : Tree, l : String, txt : String) : [H.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 ->
print [ 'Warning. Local link not found: ' !(string_of l) '\n' ];
[]
let compute_sitemap ((Page|External) -> Tree)
| <page name=name ..>[ <title>title (c::(Page|External) | _)* ] & p ->
let children = map c with p -> compute_sitemap p in
{ name url=(url_of_page p) title children boxes=(boxes_of p) }
| <external name=name href=h title>[] ->
{ name url=h title children=[] boxes=[] }
let ul([H.li*] -> [H.ul?]) [] -> [] | l -> [ <ul>l ]
let ol(([H.li*],{style=?String}) -> [H.ol?])
| ([],_) -> []
| (l,s) -> [ <ol (s)>l ]
let display_sitemap (h : Tree) : H.li =
let ch = map h . children with x -> display_sitemap x in
<li>[ <a href=(h . url)>[ '[' !(h . title) ']' ] !(h . boxes); (ul ch) ]
let boxes_of (Page -> [H.ul?])
<page ..>[ (items::Item | _)*] & p ->