Cameleon2: Report

The Report tool aims to make generation of XML documents from OCaml applications easier. The main idea is to separate the structure of the document from the information computed by the application and placed in the document. For example, in the following document:
<h1>Crêpes</h1> <list> <item>flour</item> <item>eggs</item> <item>sugar</item> </list>
<h1> </h1> <list> <item> </item> <item> </item> <item> </item> </list>
To build our XML document, we must therefore describe its structure as well as the way to fill it with information. Then, at runtime, the application will use this description to generate the final XML document.
In practice, Report allows to graphically describe the document (structure + information), and then to generate OCaml code which uses the Report library. In particular, this library contains a function which computes a document description to produce the final XML document. An important point is that the way to compute the information needed in the document is given in the form of OCaml code.
The Report module defines the types used to describe a document :
(** A report element. *)
type 'a report_ele =
| Leaf of (unit -> string)
| Tag of 'a tag
| List of 'a liste
| Cond of 'a cond
| Sub of 'a sub
(** A tag. *)
and 'a tag = {
mutable tag : string ;
mutable atts : (string * (unit -> string)) list ;
mutable tag_subs : 'a report_ele list
}
(** A list of substructures. *)
and 'a liste =
{ mutable list_subs : ('a -> 'a report_ele list) ;
mutable f : (unit -> 'a list) ;
}
(** Conditional *)
and 'a cond =
{ mutable cond : unit -> bool ;
mutable subs_then : 'a report_ele list ;
mutable subs_else : 'a report_ele list ;
}
(** Subreport *)
and 'a sub =
{
mutable sub_rep : unit -> 'a report ;
}
(** A report description is a list of report elements. *)
and 'a report = {
mutable rep_eles : 'a report_ele list ;
}
The document example of the introduction could be described as in following section.
let rec report =
({
rep_eles = [
Tag { tag = "h1" ; atts = [] ;
tag_subs = [
Leaf (fun () -> "Crepes");
] } ;
Tag { tag = "list" ; atts = [] ;
tag_subs = [
( let rec ing =
{ f = (fun () -> ing_of_recipe "Crêpes") ;
current = (Report.coerce 0) ;
list_subs = [
Tag { tag = "item" ; atts = [] ;
tag_subs = [ Leaf (fun () -> ing.current.ing_name) ] }
] }
in
List (Report.coerce ing))
]
}
]
} : int report)
The call to Report.coerce is necessary to force the type but type constraints are already satisfied (notably the use of the current field) at this point.
As we can see, this structure can quickly become a pain to define and read. To solve this problem, the report_gui tool allows to graphically define the document description and the report tool generates the OCaml code of this structure.
Moreover, the report value could have had parameters; this is a way to parametrize the final XML document.
The Report module contains the following functions :
(** Coerce report elements. *) val coerce : 'a -> 'b (** Compute a report and print it to the given formatter. *) val compute : ?html: bool -> Format.formatter -> 'a report -> unit (** Compute a report and print it in a file. *) val compute_file : ?html: bool -> string -> 'a report -> unit
The coerce function is used to insert a 'a report_ele into the node of a 'b report_ele, when 'a cannot be used as 'b. This function must only be used for this purpose, as in the example above.
The compute function takes a formatter and a document description and computes this description to generate the final XML document in the given formatter. The html optional parameter allows not to close some tags (like br ) to generate HTML compliant documents.
The compute_file function acts like compute but writes in the given file instead of a formatter.
The report.gui tool allows to describe a document (structure + code to fill it with information), as well as the parameters of this document (these parameters become parameters of the report value in the code example). The document is describe through a graphical user interface with a tree oriented view.
The grapical editor is launched by the following command:
report.gui.{x,byte} [options] file [file2 [file3 ...]]
The report tool generates the OCaml code of the document description, using the types defined in the Report library.
The code generator is launched by the following command:
report.{x,byte} [options] file
The following options are supported:
Cameleon2: Report
