package xtmpl

  1. Overview
  2. Docs

Templating XML trees.

XML trees which are rewritten using callback rules provided by the env environment.

A complete description of the templating rules is available in the Templating engine section below.

module SMap = Xml.SMap
module Name_set = Xml.Name_set
module Str = Re.Str

XML documents

module Attributes = Xml.Name_map
module P : Types.P with module Attributes = Xml.Name_map and type attr_value = X.tree list
module X : Types.S with type name = Attributes.key and type attr_value = P.attr_value and type attributes = P.attr_value Attributes.t and type data = unit
module PP : sig ... end
include module type of struct include X end
type name = Attributes.key
type attr_value = P.attr_value
type attributes = P.attr_value Attributes.t
type data = unit
type proc_inst = X.proc_inst = {
  1. loc : Types.loc option;
  2. app : name;
  3. args : string;
}
type xml_decl = X.xml_decl = {
  1. loc : Types.loc option;
  2. atts : attributes;
}
type doctype = X.doctype = {
  1. loc : Types.loc option;
  2. name : name;
  3. args : string;
}
type node = X.node = {
  1. loc : Types.loc option;
  2. name : name;
  3. atts : attributes;
  4. subs : tree list;
  5. data : data;
}
and tree = X.tree =
  1. | E of node
  2. | D of Types.cdata
  3. | C of Types.comment
  4. | PI of proc_inst
type prolog_misc = X.prolog_misc =
  1. | PC of Types.comment
  2. | PPI of proc_inst
type prolog = X.prolog = {
  1. decl : xml_decl option;
  2. misc : prolog_misc list;
  3. doctype : doctype option;
}
type doc = X.doc = {
  1. prolog : prolog;
  2. elements : tree list;
}
val compare_doc : doc -> doc -> int
val compare_tree : tree -> tree -> int

Constructors

val node_ : ?loc:Types.loc -> name -> ?atts:attributes -> ?data:data -> tree list -> node
val node : ?loc:Types.loc -> name -> ?atts:attributes -> ?data:data -> tree list -> tree
val cdata_ : ?loc:Types.loc -> ?quoted:bool -> string -> Types.cdata
val cdata : ?loc:Types.loc -> ?quoted:bool -> string -> tree
val comment_ : ?loc:Types.loc -> string -> Types.comment
val comment : ?loc:Types.loc -> string -> tree
val prolog_comment : ?loc:Types.loc -> string -> Types.comment
val pi_ : ?loc:Types.loc -> name -> string -> proc_inst
val pi : ?loc:Types.loc -> name -> string -> tree
val prolog_pi : ?loc:Types.loc -> name -> string -> proc_inst
val xml_decl : ?loc:Types.loc -> attributes -> xml_decl
val doctype : ?loc:Types.loc -> name -> string -> doctype
val prolog : ?decl:xml_decl -> ?doctype:doctype -> prolog_misc list -> prolog
val doc : prolog -> tree list -> doc
val doc_empty : unit -> doc

Handling attributes

val get_att : attributes -> name -> attr_value option

get_att atts name returns the value associated to given attribute, if any.

val opt_att : attributes -> ?def:attr_value -> name -> attr_value

opt_att atts ?def name returns the value associated to given attribute, or the default value specified by ?def. If def is not specified, P.default_attr_value is used.

val atts_of_list : ?atts:attributes -> (name * attr_value) list -> attributes

atts_of_list list returns a attributes structure from the given list of pairs (name, value) ; (name, value) ; ....

  • parameter atts

    can be used to specify an existing attributes structure to add bindings to, instead of starting from an empty one.

val atts_one : ?atts:attributes -> name -> attr_value -> attributes

atts_one ?atts name value is like atts_of_list but for one attribute.

val atts_remove : name -> attributes -> attributes

atts_remove name attributes removes the binding to name from the attributes.

val atts_replace : name -> attr_value -> attributes -> attributes

atts_replace name value attributes adds a new bindings from name to value in attributes. If name was previously bound, the previous binding is removed.

val atts_fold : (name -> attr_value -> 'acc -> 'acc) -> attributes -> 'acc -> 'acc

Printers

val pp_doc : Format.formatter -> doc -> unit
val pp : Format.formatter -> doc -> unit
val pp_attr : ?first:bool -> Format.formatter -> name -> attr_value -> unit
val pp_attributes : Format.formatter -> attributes -> unit
val pp_trees : Format.formatter -> tree list -> unit
val string_of_xml : tree -> string

Text extraction

val doctype_name : doc -> name option
val text_of_xmls : tree list -> string
val text_of_range : tree -> tree -> tree option -> string
val atts_empty : attributes

Empty map of attributes

Errors

type rewrite_stack = (name * attributes * tree list * Types.loc option) list

To catch eventual infinite loops in rewriting, we keep a stack of the rules called.

val string_of_rewrite_stack : ((string * string) * tree list Attributes.t * tree list * 'a) list -> string

String representation of the given rewrite stack.

type Types.error +=
  1. | Loop of rewrite_stack
    (*

    The Loop error is raised when the rewrite stack is higher than a default value of 100. This value can be changed by setting the XTMPL_REWRITE_DEPTH_LIMIT environment variable.

    *)
  2. | Parse_attribute_error of Types.loc option * Xml.name * string
  3. | Invalid_attribute_value of string * tree list
  4. | Fixpoint_limit of int
val loop_error : rewrite_stack -> 'a
val parse_attribute_error : Types.loc option -> Xml.name -> string -> 'a
val invalid_attribute_value : string -> tree list -> 'a
val fixpoint_limit : int -> 'a
val string_of_error : Types.error -> string option

Special tag and attributes

val tag_env : string

The environment tag, currently "env_".

See the template rules in the Templating engine section below for more information about this tag.

val att_defer : string

The defer attribute, currently "defer_". See the engine section for details.

val att_escamp : string

The escamp attribute, currently "escamp_". This attribute is used when converting XML to string or reading XML from a string. The CDATA associated to this attribute indicates the other attributes in which the ampersands must be escaped (when parsing XML from an attribute string) or unescaped (when printing XML to an attribute string). This is useful for urls with &, for example in <a href="..."> nodes.

Example: In <a escamp_="href", href="http://foo.fr?v1=3amp;v2=4">...</a>. As attributes are parsed as XML, setting the escamp_ attribute to "href" will make the ampersand escaped. The attribute is kept during rewriting. When the XML tree will be converted to a string, the escamp_ attribute will be removed. Several attribute names can be indicated, using ',' or ';' as separator, as in <a escamp_="href, foo, gee:buz" href="..." ...>...</a> .

val att_protect : string

The protect attribute, currently "protect_". See the engine section for details. This attribute is removed when a XML tree is converted to a string, as for att_escamp.

Mapping to Xml documents

val to_xml : ?xml_atts:bool -> X.tree -> Xml.tree

Convert to a Xml.tree. Optional argument xml_atts indicates whether the code in attributes remains valid XML or not. Default is true but it should be set to false when outputting final documents like XHTML pages.

val to_xmls : ?xml_atts:bool -> X.tree list -> Xml.tree list

Same as to_xml but for a list of trees.

val to_xml_attributes : ?xml_atts:bool -> X.attributes -> Xml.attributes

Same as to_xml but for a map of attributes.

val to_doc : ?xml_atts:bool -> X.doc -> Xml.doc

Same as to_xml but for a doc.

val to_prolog : ?xml_atts:bool -> X.prolog -> Xml.prolog

Same as to_xml but for a document prolog.

Mapping from a Xml documents

val from_xml : Xml.tree -> X.tree

Convert from a Xml.tree list. Attribute values must be valid XML.

val from_xmls : Xml.tree list -> X.tree list

Same as from_xml but for a list of trees.

val from_xml_attributes : Xml.attributes -> X.attributes
val from_doc : Xml.doc -> X.doc

Convert from a Xml.doc. Attribute values must be valid XML.

val from_prolog : Xml.prolog -> X.prolog

Convert from a Xml.prolog.

Input/output

val to_string : ?xml_atts:bool -> X.tree list -> string

Output a tree list to a string. See to_xml about xml_atts argument.

val doc_to_string : ?xml_atts:bool -> X.doc -> string

Output an XML document to a string. See to_xml about xml_atts argument.

val from_string : ?pos_start:Types.pos -> string -> X.tree list

Parses a string as tree list.

val doc_from_string : ?pos_start:Types.pos -> string -> X.doc

Parses a doc.

val from_file : string -> X.tree list

Same as from_string but reads from a file.

val doc_from_file : string -> X.doc

Same as doc_from_string but reads from a file.

Utils

val get_att_cdata : attributes -> name -> string option

Same as get_att but return a string s only if name is bound to a single CDATA XML node ([D s]). In particular, if name is bound to a list of XML tree, or to a single tree which is not a CDATA, the function returns None.

val opt_att_cdata : attributes -> ?def:string -> name -> string

Same as opt_att but looking for CDATA bounded values, as in get_att_cdata.

val upto_first_element : tree list -> tree list

upto_first_element trees returns the list of trees until the first E element, included.

  • raises Not_found

    if there is no element in the list.

val merge_cdata_list : tree list -> tree list

Same as merge_cdata but taking a tree list.

val merge_cdata : tree -> tree

Recursively merge sibling D nodes into one D node.

Environment

An env is a name-to-callback associative map. In addition to basic manipulation functions, the functions env_add_xml and env_of_list provide convenient shortcuts for common operations.

The environments are immutable, all mutating operations return new environments.

type 'a env = {
  1. env_ns : Iri.t SMap.t;
  2. env_map : 'a callback Attributes.t;
}
and 'a callback = 'a -> 'a env -> ?loc:Types.loc -> attributes -> tree list -> 'a * tree list
val env_empty : unit -> 'a env

An environment that contains no binding.

exception No_change

This exception can be raised by callbacks to indicate that the node to be rewritten remains unchanged.

val env_add_cb : ?prefix:SMap.key -> string -> 'a callback -> 'a env -> 'a env

Add a binding to an environment.

env_add_cb "double" (fun acc _ _ xml -> (acc, xml @ xml)) binds the key ("", "double") to a callback that doubles an XML subtree.

env_add_cb ~prefix: "foo" "double" (fun acc _ _ xml -> (acc, xml @ xml)) does the same but for the key ("foo", "double").

If the same key was already bound, the previous binding is replaced.

Opional argument prefix is "" by default.

val env_add_xml : ?prefix:SMap.key -> string -> tree list -> 'a env -> 'a env

Bind a callback that returns some XML.

The most frequent operation performed by a callback is to return constant XML subtrees. This convenience function lets you provide the XML subtrees.

env_add_xml "logo" [ E (("","img"), atts_one ("","src") [D "logo.png"], []) ] env binds the key ("","logo") to a callback that returns an XHTML image tag.

Optional argument prefix can be used to specify a prefix for the rule name. Default is "".

val env_get : (SMap.key * string) -> 'a env -> 'a callback option

Get a binding from an environment. If the binding is not found, returns None.

val env_of_list : ?env:'a env -> ((SMap.key * string) * 'a callback) list -> 'a env

Add several bindings at once.

This convenience function saves you the effort of calling env_add_cb several times yourself.

env_of_list ~env:env [ (ns1, k1), f1 ; (ns2, k2), f2 ] is equivalent to env_add_cb ~prefix: ns1 k1 f1 (env_add_cb ~prefix: ns2 k2 f2 env). This means that one key is present twice in the list, the first association in the list will hide the second one in the resulting environment.

The env optional argument is the environment to which bindings are added. If not provided, env_empty () is used.

val string_of_env : 'a env -> string

String representation of all the keys in the environment.

Templating engine

The apply_* functions apply a given environment and data to XML tree(s). These trees are given as parameter (apply_to_xmls) or can be read from a file (apply_to_file), or a string (apply_to_string).

The functions return the result of the rewrite as XML trees, or can write it to a file (apply_into_file). They also return data as the result of the callbacks called, as in a classic fold function (callbacks take the data in parameter, as the environment, the attributes and subnodes of the rewritten node).

The rewrite rules are applied until a fix-point is reached. If the XTMPL_FIXPOINT_LIMIT environment variable contains a valid integer n, it is used as a fix-point limit: if no fix-point is reached in n iterations, then a Failure exception is raised.

  1. A single iteration descends recursively into the XML tree. If an element has a callback associated in the environment, then the callback is applied to the current data and the node's attributes and children.

    Example: consider the following XML:

    <album author="Rammstein" name="Reise, Reise">
      <track>Los</track>
      <track>Mein Teil</track>
    </album>

    This would look for a callback bound to ("","album") in the environment and call it using callback data env {("","author")->[ D "Rammstein"]|("","name")->[D "Reise, Reise"]} xml where env is the current environment and xml represents the two children <track>..</track> elements.

  2. The callback returns a pair composed of (maybe new) data and a new list of elements that is used instead of the old element.

    Example: assuming that the environnement was build using env_add_cb "x2" (fun data _ _ xml -> (data, xml @ xml)) env, then <x2>A</x2> is rewritten as AA.

  3. The engine then recursively descends into those replaced elements (this means that a poorly conceived rule set may well never terminate).

    Example: <x2><x2>A</x2></x2> is first rewritten as <x2>A</x2><x2>A</x2>, and then as AAAA.

  4. The env_ element (see tag_env is a special case: it is automatically replaced with its children (as if its callback was (fun data _ _ xml -> (data, xml))).

    env_ effectively changes the environment used when processing its children by adding the bindings defined by its attributes (using env_add_xml).

    Example: <env_ a="&lt;b&gt;A&lt;/b&gt;"><a/></env_> is replaced by <a/>, which in turn is replaced by <b>A</b>.

  5. If an element has a defer_ attribute (that is greater than zero), then it is not processed and the attribute is decremented by one, and the process recursively applies to its children.

    Example: <x2 defer_="1"><x2>A</x2></x2> is rewritten as <x2 defer_="0">AA</x2>. The next iteration will effectively apply the rule to the node and return AAAA.

  6. If an element has a protect_ attribute, then the value must be CDATA and contains a list of names to remove from the environment when descending in the children. The names are separated by ',' or ';', for example: <foo protect_="title,id,foo:bar" ..>...</foo>.
val apply_to_xmls : 'a -> 'a env -> P.attr_value -> 'a * P.attr_value

As apply_to_string, but applies to a list of XML trees.

val apply_to_xml : 'a -> 'a env -> X.tree -> 'a * P.attr_value

As apply_to_string, but applies to a single XML tree.

val apply_to_doc : 'a -> 'a env -> doc -> 'a * doc

As apply_to_string, but applies to a doc.

val apply_to_string : 'a -> 'a env -> string -> 'a * tree list

Applies as many iterations as necessary to a piece of XML (represented as an unparsed string) to reach a fix-point.

See Templating engine for how an iteration is applied.

val apply_to_file : 'a -> 'a env -> string -> 'a * P.attr_value

As apply_to_string, but reads the XML from a file.

val apply_into_file : 'a -> ?head:string -> 'a env -> infile:string -> outfile:string -> 'a

As apply_to_file, but writes the result back to a file.

For instance, apply_to_file data env ~infile:"source.xml" ~outfile: "dest.xml".

When provided, optional argument head is prepended to the XML that is output to the file. By default, nothing is prepended.

val apply_string_into_file : 'a -> ?head:string -> 'a env -> outfile:string -> string -> 'a

As apply_into_file, but read the XML from a string instead of a file.

OCaml

Innovation. Community. Security.