]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/DEVEL/pxp/pxp/doc/manual/html/x738.html
Initial revision
[helm.git] / helm / DEVEL / pxp / pxp / doc / manual / html / x738.html
diff --git a/helm/DEVEL/pxp/pxp/doc/manual/html/x738.html b/helm/DEVEL/pxp/pxp/doc/manual/html/x738.html
new file mode 100644 (file)
index 0000000..6741801
--- /dev/null
@@ -0,0 +1,1036 @@
+<HTML
+><HEAD
+><TITLE
+>Example: An HTML backend for the readme
+DTD</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.46"><LINK
+REL="HOME"
+TITLE="The PXP user's guide"
+HREF="index.html"><LINK
+REL="UP"
+TITLE="Using PXP"
+HREF="c533.html"><LINK
+REL="PREVIOUS"
+TITLE="Class-based processing of the node tree"
+HREF="x675.html"><LINK
+REL="NEXT"
+TITLE="The objects representing the document"
+HREF="c893.html"><LINK
+REL="STYLESHEET"
+TYPE="text/css"
+HREF="markup.css"></HEAD
+><BODY
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>The PXP user's guide</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="x675.html"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+>Chapter 2. Using <SPAN
+CLASS="ACRONYM"
+>PXP</SPAN
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="c893.html"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="SECT.README.TO-HTML"
+>2.4. Example: An HTML backend for the <I
+CLASS="EMPHASIS"
+>readme</I
+>
+DTD</A
+></H1
+><P
+>The converter from <I
+CLASS="EMPHASIS"
+>readme</I
+> documents to HTML
+documents follows strictly the approach to define one class per element
+type. The HTML code is similar to the <I
+CLASS="EMPHASIS"
+>readme</I
+> source,
+because of this most elements can be converted in the following way: Given the
+input element 
+
+<PRE
+CLASS="PROGRAMLISTING"
+>&#60;e&#62;content&#60;/e&#62;</PRE
+>
+
+the conversion text is the concatenation of a computed prefix, the recursively
+converted content, and a computed suffix. </P
+><P
+>Only one element type cannot be handled by this scheme:
+<TT
+CLASS="LITERAL"
+>footnote</TT
+>. Footnotes are collected while they are found in
+the input text, and they are printed after the main text has been converted and
+printed. </P
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN747"
+>2.4.1. Header</A
+></H2
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>open Pxp_types
+open Pxp_document</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN751"
+>2.4.2. Type declarations</A
+></H2
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>class type footnote_printer =
+  object
+    method footnote_to_html : store_type -&gt; out_channel -&gt; unit
+  end
+
+and store_type =
+  object
+    method alloc_footnote : footnote_printer -&gt; int
+    method print_footnotes : out_channel -&gt; unit
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN755"
+>2.4.3. Class <TT
+CLASS="LITERAL"
+>store</TT
+></A
+></H2
+><P
+>The <TT
+CLASS="LITERAL"
+>store</TT
+> is a container for footnotes. You can add a
+footnote by invoking <TT
+CLASS="LITERAL"
+>alloc_footnote</TT
+>; the argument is an
+object of the class <TT
+CLASS="LITERAL"
+>footnote_printer</TT
+>, the method returns the
+number of the footnote. The interesting property of a footnote is that it can
+be converted to HTML, so a <TT
+CLASS="LITERAL"
+>footnote_printer</TT
+> is an object
+with a method <TT
+CLASS="LITERAL"
+>footnote_to_html</TT
+>. The class
+<TT
+CLASS="LITERAL"
+>footnote</TT
+> which is defined below has a compatible method
+<TT
+CLASS="LITERAL"
+>footnote_to_html</TT
+> such that objects created from it can be
+used as <TT
+CLASS="LITERAL"
+>footnote_printer</TT
+>s.</P
+><P
+>The other method, <TT
+CLASS="LITERAL"
+>print_footnotes</TT
+> prints the footnotes as
+definition list, and is typically invoked after the main material of the page
+has already been printed. Every item of the list is printed by
+<TT
+CLASS="LITERAL"
+>footnote_to_html</TT
+>.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>class store =
+  object (self)
+
+    val mutable footnotes = ( [] : (int * footnote_printer) list )
+    val mutable next_footnote_number = 1
+
+    method alloc_footnote n =
+      let number = next_footnote_number in
+      next_footnote_number &lt;- number+1;
+      footnotes &lt;- footnotes @ [ number, n ];
+      number
+
+    method print_footnotes ch =
+      if footnotes &lt;&gt; [] then begin
+       output_string ch "&lt;hr align=left noshade=noshade width=\"30%\"&gt;\n";
+       output_string ch "&lt;dl&gt;\n";
+       List.iter
+         (fun (_,n) -&gt; 
+            n # footnote_to_html (self : #store_type :&gt; store_type) ch)
+         footnotes;
+       output_string ch "&lt;/dl&gt;\n";
+      end
+
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN772"
+>2.4.4. Function <TT
+CLASS="LITERAL"
+>escape_html</TT
+></A
+></H2
+><P
+>This function converts the characters &lt;, &gt;, &amp;, and " to their HTML
+representation. For example, 
+<TT
+CLASS="LITERAL"
+>escape_html "&lt;&gt;" = "&amp;lt;&amp;gt;"</TT
+>. Other
+characters are left unchanged.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>let escape_html s =
+  Str.global_substitute
+    (Str.regexp "&lt;\\|&gt;\\|&amp;\\|\"")
+    (fun s -&gt;
+      match Str.matched_string s with
+        "&lt;" -&gt; "&amp;lt;"
+      | "&gt;" -&gt; "&amp;gt;"
+      | "&amp;" -&gt; "&amp;amp;"
+      | "\"" -&gt; "&amp;quot;"
+      | _ -&gt; assert false)
+    s
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN778"
+>2.4.5. Virtual class <TT
+CLASS="LITERAL"
+>shared</TT
+></A
+></H2
+><P
+>This virtual class is the abstract superclass of the extension classes shown
+below. It defines the standard methods <TT
+CLASS="LITERAL"
+>clone</TT
+>,
+<TT
+CLASS="LITERAL"
+>node</TT
+>, and <TT
+CLASS="LITERAL"
+>set_node</TT
+>, and declares the type
+of the virtual method <TT
+CLASS="LITERAL"
+>to_html</TT
+>. This method recursively
+traverses the whole element tree, and prints the converted HTML code to the
+output channel passed as second argument. The first argument is the reference
+to the global <TT
+CLASS="LITERAL"
+>store</TT
+> object which collects the footnotes.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class virtual shared =
+  object (self)
+
+    (* --- default_ext --- *)
+
+    val mutable node = (None : shared node option)
+
+    method clone = {&lt; &gt;} 
+    method node =
+      match node with
+          None -&gt;
+            assert false
+        | Some n -&gt; n
+    method set_node n =
+      node &lt;- Some n
+
+    (* --- virtual --- *)
+
+    method virtual to_html : store -&gt; out_channel -&gt; unit
+
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN788"
+>2.4.6. Class <TT
+CLASS="LITERAL"
+>only_data</TT
+></A
+></H2
+><P
+>This class defines <TT
+CLASS="LITERAL"
+>to_html</TT
+> such that the character data of
+the current node is converted to HTML. Note that <TT
+CLASS="LITERAL"
+>self</TT
+> is an
+extension object, <TT
+CLASS="LITERAL"
+>self # node</TT
+> is the node object, and
+<TT
+CLASS="LITERAL"
+>self # node # data</TT
+> returns the character data of the node. 
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class only_data =
+  object (self)
+    inherit shared
+
+    method to_html store ch =
+      output_string ch (escape_html (self # node # data))
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN797"
+>2.4.7. Class <TT
+CLASS="LITERAL"
+>readme</TT
+></A
+></H2
+><P
+>This class converts elements of type <TT
+CLASS="LITERAL"
+>readme</TT
+> to HTML. Such an
+element is (by definition) always the root element of the document. First, the
+HTML header is printed; the <TT
+CLASS="LITERAL"
+>title</TT
+> attribute of the element
+determines the title of the HTML page. Some aspects of the HTML page can be
+configured by setting certain parameter entities, for example the background
+color, the text color, and link colors. After the header, the
+<TT
+CLASS="LITERAL"
+>body</TT
+> tag, and the headline have been printed, the contents
+of the page are converted by invoking <TT
+CLASS="LITERAL"
+>to_html</TT
+> on all
+children of the current node (which is the root node). Then, the footnotes are
+appended to this by telling the global <TT
+CLASS="LITERAL"
+>store</TT
+> object to print
+the footnotes. Finally, the end tags of the HTML pages are printed.</P
+><P
+>This class is an example how to access the value of an attribute: The value is
+determined by invoking <TT
+CLASS="LITERAL"
+>self # node # attribute "title"</TT
+>. As
+this attribute has been declared as CDATA and as being required, the value has
+always the form <TT
+CLASS="LITERAL"
+>Value s</TT
+> where <TT
+CLASS="LITERAL"
+>s</TT
+> is the
+string value of the attribute. </P
+><P
+>You can also see how entity contents can be accessed. A parameter entity object
+can be looked up by <TT
+CLASS="LITERAL"
+>self # node # dtd # par_entity "name"</TT
+>,
+and by invoking <TT
+CLASS="LITERAL"
+>replacement_text</TT
+> the value of the entity
+is returned after inner parameter and character entities have been
+processed. Note that you must use <TT
+CLASS="LITERAL"
+>gen_entity</TT
+> instead of
+<TT
+CLASS="LITERAL"
+>par_entity</TT
+> to access general entities.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>class readme =
+  object (self)
+    inherit shared
+
+    method to_html store ch =
+      (* output header *)
+      output_string 
+       ch "&lt;!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\"&gt;";
+      output_string
+       ch "&lt;!-- WARNING! This is a generated file, do not edit! --&gt;\n";
+      let title = 
+       match self # node # attribute "title" with
+           Value s -&gt; s
+         | _ -&gt; assert false
+      in
+      let html_header, _ =
+       try (self # node # dtd # par_entity "readme:html:header") 
+            # replacement_text
+       with WF_error _ -&gt; "", false in
+      let html_trailer, _ =
+       try (self # node # dtd # par_entity "readme:html:trailer")
+            # replacement_text
+       with WF_error _ -&gt; "", false in
+      let html_bgcolor, _ =
+       try (self # node # dtd # par_entity "readme:html:bgcolor")
+            # replacement_text
+       with WF_error _ -&gt; "white", false in
+      let html_textcolor, _ =
+       try (self # node # dtd # par_entity "readme:html:textcolor")
+            # replacement_text
+       with WF_error _ -&gt; "", false in
+      let html_alinkcolor, _ =
+       try (self # node # dtd # par_entity "readme:html:alinkcolor")
+            # replacement_text
+       with WF_error _ -&gt; "", false in
+      let html_vlinkcolor, _ =
+       try (self # node # dtd # par_entity "readme:html:vlinkcolor")
+            # replacement_text
+       with WF_error _ -&gt; "", false in
+      let html_linkcolor, _ =
+       try (self # node # dtd # par_entity "readme:html:linkcolor")
+            # replacement_text
+       with WF_error _ -&gt; "", false in
+      let html_background, _ =
+       try (self # node # dtd # par_entity "readme:html:background")
+            # replacement_text
+       with WF_error _ -&gt; "", false in
+
+      output_string ch "&lt;html&gt;&lt;header&gt;&lt;title&gt;\n";
+      output_string ch (escape_html title);
+      output_string ch "&lt;/title&gt;&lt;/header&gt;\n";
+      output_string ch "&lt;body ";
+      List.iter
+       (fun (name,value) -&gt;
+          if value &lt;&gt; "" then 
+            output_string ch (name ^ "=\"" ^ escape_html value ^ "\" "))
+       [ "bgcolor",    html_bgcolor;
+         "text",       html_textcolor;
+         "link",       html_linkcolor;
+         "alink",      html_alinkcolor;
+         "vlink",      html_vlinkcolor;
+       ];
+      output_string ch "&gt;\n";
+      output_string ch html_header;
+      output_string ch "&lt;h1&gt;";
+      output_string ch (escape_html title);
+      output_string ch "&lt;/h1&gt;\n";
+      (* process main content: *)
+      List.iter
+       (fun n -&gt; n # extension # to_html store ch)
+       (self # node # sub_nodes);
+      (* now process footnotes *)
+      store # print_footnotes ch;
+      (* trailer *)
+      output_string ch html_trailer;
+      output_string ch "&lt;/html&gt;\n";
+
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN817"
+>2.4.8. Classes <TT
+CLASS="LITERAL"
+>section</TT
+>, <TT
+CLASS="LITERAL"
+>sect1</TT
+>,
+<TT
+CLASS="LITERAL"
+>sect2</TT
+>, and <TT
+CLASS="LITERAL"
+>sect3</TT
+></A
+></H2
+><P
+>As the conversion process is very similar, the conversion classes of the three
+section levels are derived from the more general <TT
+CLASS="LITERAL"
+>section</TT
+>
+class. The HTML code of the section levels only differs in the type of the
+headline, and because of this the classes describing the section levels can be
+computed by replacing the class argument <TT
+CLASS="LITERAL"
+>the_tag</TT
+> of
+<TT
+CLASS="LITERAL"
+>section</TT
+> by the HTML name of the headline tag.</P
+><P
+>Section elements are converted to HTML by printing a headline and then
+converting the contents of the element recursively. More precisely, the first
+sub-element is always a <TT
+CLASS="LITERAL"
+>title</TT
+> element, and the other
+elements are the contents of the section. This structure is declared in the
+DTD, and it is guaranteed that the document matches the DTD. Because of this
+the title node can be separated from the rest without any checks.</P
+><P
+>Both the title node, and the body nodes are then converted to HTML by calling
+<TT
+CLASS="LITERAL"
+>to_html</TT
+> on them.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>class section the_tag =
+  object (self)
+    inherit shared
+
+    val tag = the_tag
+
+    method to_html store ch =
+      let sub_nodes = self # node # sub_nodes in
+      match sub_nodes with
+         title_node :: rest -&gt;
+           output_string ch ("&lt;" ^ tag ^ "&gt;\n");
+           title_node # extension # to_html store ch;
+           output_string ch ("\n&lt;/" ^ tag ^ "&gt;");
+           List.iter
+             (fun n -&gt; n # extension # to_html store ch)
+             rest
+       | _ -&gt;
+           assert false
+  end
+;;
+
+class sect1 = section "h1";;
+class sect2 = section "h3";;
+class sect3 = section "h4";;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN833"
+>2.4.9. Classes <TT
+CLASS="LITERAL"
+>map_tag</TT
+>, <TT
+CLASS="LITERAL"
+>p</TT
+>,
+<TT
+CLASS="LITERAL"
+>em</TT
+>, <TT
+CLASS="LITERAL"
+>ul</TT
+>, <TT
+CLASS="LITERAL"
+>li</TT
+></A
+></H2
+><P
+>Several element types are converted to HTML by simply mapping them to
+corresponding HTML element types. The class <TT
+CLASS="LITERAL"
+>map_tag</TT
+>
+implements this, and the class argument <TT
+CLASS="LITERAL"
+>the_target_tag</TT
+>
+determines the tag name to map to. The output consists of the start tag, the
+recursively converted inner elements, and the end tag.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class map_tag the_target_tag =
+  object (self)
+    inherit shared
+
+    val target_tag = the_target_tag
+
+    method to_html store ch =
+      output_string ch ("&lt;" ^ target_tag ^ "&gt;\n");
+      List.iter
+       (fun n -&gt; n # extension # to_html store ch)
+       (self # node # sub_nodes);
+      output_string ch ("\n&lt;/" ^ target_tag ^ "&gt;");
+  end
+;;
+
+class p = map_tag "p";;
+class em = map_tag "b";;
+class ul = map_tag "ul";;
+class li = map_tag "li";;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN844"
+>2.4.10. Class <TT
+CLASS="LITERAL"
+>br</TT
+></A
+></H2
+><P
+>Element of type <TT
+CLASS="LITERAL"
+>br</TT
+> are mapped to the same HTML type. Note
+that HTML forbids the end tag of <TT
+CLASS="LITERAL"
+>br</TT
+>.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class br =
+  object (self)
+    inherit shared
+
+    method to_html store ch =
+      output_string ch "&lt;br&gt;\n";
+      List.iter
+       (fun n -&gt; n # extension # to_html store ch)
+       (self # node # sub_nodes);
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN851"
+>2.4.11. Class <TT
+CLASS="LITERAL"
+>code</TT
+></A
+></H2
+><P
+>The <TT
+CLASS="LITERAL"
+>code</TT
+> type is converted to a <TT
+CLASS="LITERAL"
+>pre</TT
+>
+section (preformatted text). As the meaning of tabs is unspecified in HTML,
+tabs are expanded to spaces.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class code =
+  object (self)
+    inherit shared
+
+    method to_html store ch =
+      let data = self # node # data in
+      (* convert tabs *)
+      let l = String.length data in
+      let rec preprocess i column =
+       (* this is very ineffective but comprehensive: *)
+       if i &lt; l then
+         match data.[i] with
+             '\t' -&gt;
+               let n = 8 - (column mod 8) in
+               String.make n ' ' ^ preprocess (i+1) (column + n)
+           | '\n' -&gt;
+               "\n" ^ preprocess (i+1) 0
+           | c -&gt;
+               String.make 1 c ^ preprocess (i+1) (column + 1)
+       else
+         ""
+      in
+      output_string ch "&lt;p&gt;&lt;pre&gt;";
+      output_string ch (escape_html (preprocess 0 0));
+      output_string ch "&lt;/pre&gt;&lt;/p&gt;";
+
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN858"
+>2.4.12. Class <TT
+CLASS="LITERAL"
+>a</TT
+></A
+></H2
+><P
+>Hyperlinks, expressed by the <TT
+CLASS="LITERAL"
+>a</TT
+> element type, are converted
+to the HTML <TT
+CLASS="LITERAL"
+>a</TT
+> type. If the target of the hyperlink is given
+by <TT
+CLASS="LITERAL"
+>href</TT
+>, the URL of this attribute can be used
+directly. Alternatively, the target can be given by
+<TT
+CLASS="LITERAL"
+>readmeref</TT
+> in which case the ".html" suffix must be added to
+the file name. </P
+><P
+>Note that within <TT
+CLASS="LITERAL"
+>a</TT
+> only #PCDATA is allowed, so the contents
+can be converted directly by applying <TT
+CLASS="LITERAL"
+>escape_html</TT
+> to the
+character data contents.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class a =
+  object (self)
+    inherit shared
+
+    method to_html store ch =
+      output_string ch "&lt;a ";
+      let href =
+       match self # node # attribute "href" with
+           Value v -&gt; escape_html v
+         | Valuelist _ -&gt; assert false
+         | Implied_value -&gt;
+             begin match self # node # attribute "readmeref" with
+                 Value v -&gt; escape_html v ^ ".html"
+               | Valuelist _ -&gt; assert false
+               | Implied_value -&gt;
+                   ""
+             end
+      in
+      if href &lt;&gt; "" then
+       output_string ch ("href=\""  ^ href ^ "\"");
+      output_string ch "&gt;";
+      output_string ch (escape_html (self # node # data));
+      output_string ch "&lt;/a&gt;";
+       
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN870"
+>2.4.13. Class <TT
+CLASS="LITERAL"
+>footnote</TT
+></A
+></H2
+><P
+>The <TT
+CLASS="LITERAL"
+>footnote</TT
+> class has two methods:
+<TT
+CLASS="LITERAL"
+>to_html</TT
+> to convert the footnote reference to HTML, and
+<TT
+CLASS="LITERAL"
+>footnote_to_html</TT
+> to convert the footnote text itself.</P
+><P
+>The footnote reference is converted to a local hyperlink; more precisely, to
+two anchor tags which are connected with each other. The text anchor points to
+the footnote anchor, and the footnote anchor points to the text anchor.</P
+><P
+>The footnote must be allocated in the <TT
+CLASS="LITERAL"
+>store</TT
+> object. By
+allocating the footnote, you get the number of the footnote, and the text of
+the footnote is stored until the end of the HTML page is reached when the
+footnotes can be printed. The <TT
+CLASS="LITERAL"
+>to_html</TT
+> method stores simply
+the object itself, such that the <TT
+CLASS="LITERAL"
+>footnote_to_html</TT
+> method is
+invoked on the same object that encountered the footnote.</P
+><P
+>The <TT
+CLASS="LITERAL"
+>to_html</TT
+> only allocates the footnote, and prints the
+reference anchor, but it does not print nor convert the contents of the
+note. This is deferred until the footnotes actually get printed, i.e. the
+recursive call of <TT
+CLASS="LITERAL"
+>to_html</TT
+> on the sub nodes is done by
+<TT
+CLASS="LITERAL"
+>footnote_to_html</TT
+>. </P
+><P
+>Note that this technique does not work if you make another footnote within a
+footnote; the second footnote gets allocated but not printed.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>class footnote =
+  object (self)
+    inherit shared
+
+    val mutable footnote_number = 0
+
+    method to_html store ch =
+      let number = 
+       store # alloc_footnote (self : #shared :&gt; footnote_printer) in
+      let foot_anchor = 
+       "footnote" ^ string_of_int number in
+      let text_anchor =
+       "textnote" ^ string_of_int number in
+      footnote_number &lt;- number;
+      output_string ch ( "&lt;a name=\"" ^ text_anchor ^ "\" href=\"#" ^ 
+                        foot_anchor ^ "\"&gt;[" ^ string_of_int number ^ 
+                        "]&lt;/a&gt;" )
+
+    method footnote_to_html store ch =
+      (* prerequisite: we are in a definition list &lt;dl&gt;...&lt;/dl&gt; *)
+      let foot_anchor = 
+       "footnote" ^ string_of_int footnote_number in
+      let text_anchor =
+       "textnote" ^ string_of_int footnote_number in
+      output_string ch ("&lt;dt&gt;&lt;a name=\"" ^ foot_anchor ^ "\" href=\"#" ^ 
+                       text_anchor ^ "\"&gt;[" ^ string_of_int footnote_number ^ 
+                       "]&lt;/a&gt;&lt;/dt&gt;\n&lt;dd&gt;");
+      List.iter
+       (fun n -&gt; n # extension # to_html store ch)
+       (self # node # sub_nodes);
+      output_string ch ("\n&lt;/dd&gt;")
+  end
+;;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN889"
+>2.4.14. The specification of the document model</A
+></H2
+><P
+>This code sets up the hash table that connects element types with the exemplars
+of the extension classes that convert the elements to HTML.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>open Pxp_yacc
+
+let tag_map =
+  make_spec_from_alist
+    ~data_exemplar:(new data_impl (new only_data))
+    ~default_element_exemplar:(new element_impl (new no_markup))
+    ~element_alist:
+      [ "readme", (new element_impl (new readme));
+       "sect1",  (new element_impl (new sect1));
+       "sect2",  (new element_impl (new sect2));
+       "sect3",  (new element_impl (new sect3));
+       "title",  (new element_impl (new no_markup));
+       "p",      (new element_impl (new p));
+       "br",     (new element_impl (new br));
+       "code",   (new element_impl (new code));
+       "em",     (new element_impl (new em));
+       "ul",     (new element_impl (new ul));
+       "li",     (new element_impl (new li));
+       "footnote", (new element_impl (new footnote : #shared :&gt; shared));
+       "a",      (new element_impl (new a));
+      ]
+    ()
+;;</PRE
+></P
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="x675.html"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="c893.html"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Class-based processing of the node tree</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="c533.html"
+>Up</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>The objects representing the document</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+>
\ No newline at end of file