Previous Up Next

Chapter 3  Report

3.1  Introduction

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>Crepes</h1>
<list>
  <item>flour</item>
  <item>eggs</item>
  <item>sugar</item>
</list>
the document structure is
<h1> </h1>
<list>
  <item> </item>
  <item> </item>
  <item> </item>
</list>
while computed information is “Crepes”, “flour”, “eggs” and “sugar”.

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 library as well as the generated code are detailed in 3.2. The description of document and the use of the report tool are explained in 3.3.

3.2  The Report library

3.2.1  Types

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 (unit -> 'a report)

(** A tag. *)
and 'a tag = {
    tag : string ;
    atts : (string * (unit -> string)) list ;
    tag_subs : 'a report_ele list
  } 
    
(** A list of substructures. *)
and 'a liste =
    { list_subs : 'a report_ele list ;
      f : (unit -> 'a list) ;
      mutable current : 'a ;
    }

(** Conditional *)
and 'a cond =
    { cond : unit -> bool ;
      subs_then : 'a report_ele list ;
      subs_else : 'a report_ele list ;
    } 

(** A report description is a list of report elements. *)
and 'a report = {
    rep_eles : 'a report_ele list ;
  } 
The type report_ele is the type of the tree nodes : The document example of the introduction could be described by :
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 "Crepes") ; 
                   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 tool allows to graphically define the document description and generate the OCaml code of this structure.

Moreover, the report value could have had parameters ; this is a way to parametrize the final XML document.

3.2.2  Functions

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.

3.3  The report and report.gui tools

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 in 3.2). The document is describe through a graphical user interface with a tree oriented view.

The report tool generates the OCaml code of the document description, using the types defined in the Report library (cf. 3.2).

Here is the report command usage : report [options] description_file
The following options are supported :
-gen
Generate the OCaml code for the document described in the given file. The code is generated in a file whose name is function of description_file. If description_file has an extension, the generated file as the same name with the extension replaced by .ml. If description_file has no extension, then the generated file has the same name, with the .ml extension appended.

-o file
Generate the OCaml code in file file, instead of the default file, when the -gen option is given.

Previous Up Next