Tyxml is a library to build statically correct HTML and SVG documents.
let to_ocaml = Html.(a ~a:[a_href "ocaml.org"] [pcdata "OCaml!"])
Using TyXML ¶
To use TyXML in standalone manner, simply link the tyxml ocamlfind package and open Tyxml.
Use with another library
Creating documents with TyXML ¶
The first thing to understand about TyXML is that for most intents and purposes, it is exactly like HTML. As such, the HTML reference is still very useful. For each HTML elements or attributes, there is a combinator implementing it. The main differences are that you can use OCaml to manipulate the elements and that invalid HTML produces a type error.
Let us start by building the content of our website. For text, we use the pcdata constructor. In traditional Web fashion, we put everything in a div.
let mycontent = div [ pcdata "This is a fabulous content." ; ]
The variable mycontent is of type [> `Div] Html.elt. As we can see, the fact that this is a div is reflected in the type. HTML elements are of type elt and have a combinator of the same name, except when it's a reserved keyword (such as object_).
Our content is fabulous, but for the sake of CSS styling (and still in true Web fashion) we want to add a class to it.
let mycontent = div ~a:[a_class ["content"]] [ pcdata "This is a fabulous content." ; ]
The a_class creates a new class attribute of type [> `Class] attrib. Similarly to elements, the kind of attribute is reflect in the attrib type. We use the optional argument ~a to pass the list of attributes. This optional argument is available on all element combinators.
In order to add a title to our fabulous content, we use the h1 combinator.
let mycontent = div ~a:[a_class ["content"]] [ h1 [pcdata "A fabulous title"] ; pcdata "This is a fabulous content." ; ]
title is an example of unary combinator.
let mytitle = title (pcdata "A Fabulous Web Page")
Interlude about type errors ¶
However, what would happen if we were to try to put bold text in our title? This is not compliant! Let's try it.
let mytitle = title (b [pcdata "A Bold Web Page"]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This expression has type ([> Html_types.b ] as 'a) elt but an expression was expected of type ([< Html_types.title_content_fun ] as 'b) elt = 'b elt Type 'a = [> `B ] is not compatible with type 'b = [< `PCDATA ] The second variant type does not allow tag(s) `B
As expected, this code does not typecheck! The typechecker is unfortunately a bit unclear about the source of the error.
It tells us that the given expression has type [> b] elt (indeed, it is produced by a b constructor) but an expression is expected of type [< title_content_fun] elt (which means that is is used as content for a title element). It then tells us that, since [> b] = [> `B] and [< title_content_fun] = [< `PCDATA ], `B is not allowed inside a title.
In order to get reasonable type errors with TyXML, The -short-paths options should always be used.
Finishing up the webpage ¶
To finish our webpage, we use the body, head and html. The last two combinators have special types due to their specific constraints: head only accepts one title children and html only accepts two children: head and body.
let mypage = html (head mytitle ) (body [mycontent])
If you are using Eliom or Js_of_ocaml, this is the end of TyXML's territory. However, for standalone use, we now need to print our document as an HTML file. The standalone implementation comes with a printer, Tyxml.Html.pp, that we can use to print files:
let () = let file = open_out "index.html" in let fmt = Format.formatter_of_out_channel file in pp () fmt mypage; close_out file
Well done, you know have a very minimal (but fabulous) website! The implementation can be found here.
Other examples are available in the examples directory.
Using your own underlying implementation ¶
You can use TyXML with any underlying implementation. In order to do so, we provide a set of functors. Please consult the relevant manual.