4 Programming with the CamlTemplate Library
When reading this section, you will probably find it helpful to refer to the CamlTemplate
API documentation, which is generated by ocamldoc and provided in the doc/api
directory of the CamlTemplate distribution.
4.1 The General Procedure
The general procedure is as follows:
-
Create a template cache using Cache.create.
- Create a data model consisting of values of type Model.tvalue.
- Load a template using Cache.get_template.
- Pass the template to the merge function to generate output.
Here is `Hello, world!' with a template. The template is as follows:
Here is the message: ${message}
And here is a program that uses it:
open Printf ;;
open CamlTemplate.Model ;;
let _ =
(* Make a template cache. *)
let cache = CamlTemplate.Cache.create () in
(* Create a model. *)
let model = Hashtbl.create 4 in
Hashtbl.add model "message"
(Tstr "Hello, world!");
try
(* Get the template. *)
let tmpl =
CamlTemplate.Cache.get_template
cache "hello.tmpl"
(* Make a buffer for the output. *)
and buf = Buffer.create 256 in
(* Generate output. *)
CamlTemplate.merge tmpl model buf;
print_string (Buffer.contents buf)
with
CamlTemplate.Syntax_error msg ->
eprintf "\n%s\n" msg
| CamlTemplate.Template_error msg ->
eprintf "\n%s\n" msg ;;
There are other examples in the examples directory of the distribution.
4.2 Template Data Models
A template data model is a tree of values; these values can be scalars (strings, integers,
floats or booleans), lists, hashtables or functions. The root of the tree must be a
hashtable. In a template, an identifier by itself is the name of an entry in that root
hashtable.
Tabular data can be represented as a list of hashes of scalars. Each element in the list
represents a row in the table, and consists of a hash in which the names are column names
and the values are cell values. Such a model can be handled as shown in
Section 2.3.
4.3 Loading and Caching Templates
Once loaded and parsed, templates are cached; the Cache module provides functions
for creating template caches, getting templates from them and configuring the behaviour of
a cache (e.g. how often it is refreshed). By default, templates are loaded from files,
but you can provide a class of type source_loader to load them from another
source.
The #include and #open statements fetch the included or opened template from
the cache when the enclosing template is merged. Therefore, if an #include or #open refers to a template that doesn't exist, this won't be detected until the outer
template is merged.
Macros are stored in the templates in which they are defined. When a template containing
a macro definition changes, the macro definition is updated as well.
4.4 Threads
CamlTemplate provides optional support for multithreaded programs. If you need thread
support, in addition to linking your program with the camlTemplate library, you
must also link in camlTemplate_mt.cmo (for bytecode programs) or camlTemplate_mt.cmx (for native-code programs). This ensures that the following are
true:
-
Multiple threads can safely use the same template cache concurrently.
- Multiple threads can safely pass the same template (or different templates) to the
merge function.
- Multiple templates running in different threads can safely use the same model, as
long as no template function changes the model. (Note that none of the template
statements, including #set and #var, can change the model.) Values set
using #set and #var are visible only to the thread that set them.
4.5 Error Handling
The get_template function raises Syntax_error if it cannot parse a template.
It may also raise other exceptions if it fails to read template source code because of an
I/O error.
If a template cannot be merged because of a run-time error (e.g. a wrong data type), the
merge function raises Template_error.
If a Caml function called from a template is unable to complete successfully, it can raise
Tfun_error; this causes merge to raise Template_error.