]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/DEVEL/pxp/pxp/doc/manual/html/x675.html
Initial revision
[helm.git] / helm / DEVEL / pxp / pxp / doc / manual / html / x675.html
diff --git a/helm/DEVEL/pxp/pxp/doc/manual/html/x675.html b/helm/DEVEL/pxp/pxp/doc/manual/html/x675.html
new file mode 100644 (file)
index 0000000..cf3f473
--- /dev/null
@@ -0,0 +1,538 @@
+<HTML
+><HEAD
+><TITLE
+>Class-based processing of the node tree</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="How to parse a document from an application"
+HREF="x550.html"><LINK
+REL="NEXT"
+TITLE="Example: An HTML backend for the readme
+DTD"
+HREF="x738.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="x550.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="x738.html"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN675"
+>2.3. Class-based processing of the node tree</A
+></H1
+><P
+>By default, the parsed node tree consists of objects of the same class; this is
+a good design as long as you want only to access selected parts of the
+document. For complex transformations, it may be better to use different
+classes for objects describing different element types.</P
+><P
+>For example, if the DTD declares the element types <TT
+CLASS="LITERAL"
+>a</TT
+>,
+<TT
+CLASS="LITERAL"
+>b</TT
+>, and <TT
+CLASS="LITERAL"
+>c</TT
+>, and if the task is to convert
+an arbitrary document into a printable format, the idea is to define for every
+element type a separate class that has a method <TT
+CLASS="LITERAL"
+>print</TT
+>. The
+classes are <TT
+CLASS="LITERAL"
+>eltype_a</TT
+>, <TT
+CLASS="LITERAL"
+>eltype_b</TT
+>, and
+<TT
+CLASS="LITERAL"
+>eltype_c</TT
+>, and every class implements
+<TT
+CLASS="LITERAL"
+>print</TT
+> such that elements of the type corresponding to the
+class are converted to the output format.</P
+><P
+>The parser supports such a design directly. As it is impossible to derive
+recursive classes in O'Caml<A
+NAME="AEN688"
+HREF="#FTN.AEN688"
+>[1]</A
+>, the specialized element classes cannot be formed by
+simply inheriting from the built-in classes of the parser and adding methods
+for customized functionality. To get around this limitation, every node of the
+document tree is represented by <I
+CLASS="EMPHASIS"
+>two</I
+> objects, one called
+"the node" and containing the recursive definition of the tree, one called "the
+extension". Every node object has a reference to the extension, and the
+extension has a reference to the node. The advantage of this model is that it
+is now possible to customize the extension without affecting the typing
+constraints of the recursive node definition.</P
+><P
+>Every extension must have the three methods <TT
+CLASS="LITERAL"
+>clone</TT
+>,
+<TT
+CLASS="LITERAL"
+>node</TT
+>, and <TT
+CLASS="LITERAL"
+>set_node</TT
+>. The method
+<TT
+CLASS="LITERAL"
+>clone</TT
+> creates a deep copy of the extension object and
+returns it; <TT
+CLASS="LITERAL"
+>node</TT
+> returns the node object for this extension
+object; and <TT
+CLASS="LITERAL"
+>set_node</TT
+> is used to tell the extension object
+which node is associated with it, this method is automatically called when the
+node tree is initialized. The following definition is a good starting point
+for these methods; usually <TT
+CLASS="LITERAL"
+>clone</TT
+> must be further refined
+when instance variables are added to the class:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class custom_extension =
+  object (self)
+
+    val mutable node = (None : custom_extension node option)
+
+    method clone = {&#60; &#62;} 
+    method node =
+      match node with
+          None -&#62;
+            assert false
+        | Some n -&#62; n
+    method set_node n =
+      node &#60;- Some n
+
+  end</PRE
+>
+
+This part of the extension is usually the same for all classes, so it is a good
+idea to consider <TT
+CLASS="LITERAL"
+>custom_extension</TT
+> as the super-class of the
+further class definitions. Continuining the example of above, we can define the
+element type classes as follows:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class virtual custom_extension =
+  object (self)
+    ... clone, node, set_node defined as above ...
+
+    method virtual print : out_channel -&#62; unit
+  end
+
+class eltype_a =
+  object (self)
+    inherit custom_extension
+    method print ch = ...
+  end
+
+class eltype_b =
+  object (self)
+    inherit custom_extension
+    method print ch = ...
+  end
+
+class eltype_c =
+  object (self)
+    inherit custom_extension
+    method print ch = ...
+  end</PRE
+>
+
+The method <TT
+CLASS="LITERAL"
+>print</TT
+> can now be implemented for every element
+type separately. Note that you get the associated node by invoking
+
+<PRE
+CLASS="PROGRAMLISTING"
+>self # node</PRE
+>
+
+and you get the extension object of a node <TT
+CLASS="LITERAL"
+>n</TT
+> by writing 
+
+<PRE
+CLASS="PROGRAMLISTING"
+>n # extension</PRE
+>
+
+It is guaranteed that 
+
+<PRE
+CLASS="PROGRAMLISTING"
+>self # node # extension == self</PRE
+>
+
+always holds.</P
+><P
+>Here are sample definitions of the <TT
+CLASS="LITERAL"
+>print</TT
+>
+methods:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>class eltype_a =
+  object (self)
+    inherit custom_extension
+    method print ch = 
+      (* Nodes &#60;a&#62;...&#60;/a&#62; are only containers: *)
+      output_string ch "(";
+      List.iter
+        (fun n -&#62; n # extension # print ch)
+        (self # node # sub_nodes);
+      output_string ch ")";
+  end
+
+class eltype_b =
+  object (self)
+    inherit custom_extension
+    method print ch =
+      (* Print the value of the CDATA attribute "print": *)
+      match self # node # attribute "print" with
+        Value s       -&#62; output_string ch s
+      | Implied_value -&#62; output_string ch "&#60;missing&#62;"
+      | Valuelist l   -&#62; assert false   
+                         (* not possible because the att is CDATA *)
+  end
+
+class eltype_c =
+  object (self)
+    inherit custom_extension
+    method print ch = 
+      (* Print the contents of this element: *)
+      output_string ch (self # node # data)
+  end
+
+class null_extension =
+  object (self)
+    inherit custom_extension
+    method print ch = assert false
+  end</PRE
+></P
+><P
+>The remaining task is to configure the parser such that these extension classes
+are actually used. Here another problem arises: It is not possible to
+dynamically select the class of an object to be created. As workaround,
+<SPAN
+CLASS="ACRONYM"
+>PXP</SPAN
+> allows the user to specify <I
+CLASS="EMPHASIS"
+>exemplar objects</I
+> for
+the various element types; instead of creating the nodes of the tree by
+applying the <TT
+CLASS="LITERAL"
+>new</TT
+> operator the nodes are produced by
+duplicating the exemplars. As object duplication preserves the class of the
+object, one can create fresh objects of every class for which previously an
+exemplar has been registered.</P
+><P
+>Exemplars are meant as objects without contents, the only interesting thing is
+that exemplars are instances of a certain class. The creation of an exemplar
+for an element node can be done by:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>let element_exemplar = new element_impl extension_exemplar</PRE
+>
+
+And a data node exemplar is created by:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>let data_exemplar = new data_impl extension_exemplar</PRE
+>
+
+The classes <TT
+CLASS="LITERAL"
+>element_impl</TT
+> and <TT
+CLASS="LITERAL"
+>data_impl</TT
+>
+are defined in the module <TT
+CLASS="LITERAL"
+>Pxp_document</TT
+>. The constructors
+initialize the fresh objects as empty objects, i.e. without children, without
+data contents, and so on. The <TT
+CLASS="LITERAL"
+>extension_exemplar</TT
+> is the
+initial extension object the exemplars are associated with. </P
+><P
+>Once the exemplars are created and stored somewhere (e.g. in a hash table), you
+can take an exemplar and create a concrete instance (with contents) by
+duplicating it. As user of the parser you are normally not concerned with this
+as this is part of the internal logic of the parser, but as background knowledge
+it is worthwhile to mention that the two methods
+<TT
+CLASS="LITERAL"
+>create_element</TT
+> and <TT
+CLASS="LITERAL"
+>create_data</TT
+> actually
+perform the duplication of the exemplar for which they are invoked,
+additionally apply modifications to the clone, and finally return the new
+object. Moreover, the extension object is copied, too, and the new node object
+is associated with the fresh extension object. Note that this is the reason why
+every extension object must have a <TT
+CLASS="LITERAL"
+>clone</TT
+> method.</P
+><P
+>The configuration of the set of exemplars is passed to the
+<TT
+CLASS="LITERAL"
+>parse_document_entity</TT
+> function as third argument. In our
+example, this argument can be set up as follows:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>let spec =
+  make_spec_from_alist
+    ~data_exemplar:            (new data_impl (new null_extension))
+    ~default_element_exemplar: (new element_impl (new null_extension))
+    ~element_alist:
+       [ "a",  new element_impl (new eltype_a);
+         "b",  new element_impl (new eltype_b);
+         "c",  new element_impl (new eltype_c);
+       ]
+    ()</PRE
+>
+
+The <TT
+CLASS="LITERAL"
+>~element_alist</TT
+> function argument defines the mapping
+from element types to exemplars as associative list. The argument
+<TT
+CLASS="LITERAL"
+>~data_exemplar</TT
+> specifies the exemplar for data nodes, and
+the <TT
+CLASS="LITERAL"
+>~default_element_exemplar</TT
+> is used whenever the parser
+finds an element type for which the associative list does not define an
+exemplar. </P
+><P
+>The configuration is now complete. You can still use the same parsing
+functions, only the initialization is a bit different. For example, call the
+parser by:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>let d = parse_document_entity default_config (from_file "doc.xml") spec</PRE
+>
+
+Note that the resulting document <TT
+CLASS="LITERAL"
+>d</TT
+> has a usable type;
+especially the <TT
+CLASS="LITERAL"
+>print</TT
+> method we added is visible. So you can
+print your document by
+
+<PRE
+CLASS="PROGRAMLISTING"
+>d # root # extension # print stdout</PRE
+></P
+><P
+>This object-oriented approach looks rather complicated; this is mostly caused
+by working around some problems of the strict typing system of O'Caml. Some
+auxiliary concepts such as extensions were needed, but the practical
+consequences are low. In the next section, one of the examples of the
+distribution is explained, a converter from <I
+CLASS="EMPHASIS"
+>readme</I
+>
+documents to HTML.</P
+></DIV
+><H3
+CLASS="FOOTNOTES"
+>Notes</H3
+><TABLE
+BORDER="0"
+CLASS="FOOTNOTES"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="LEFT"
+VALIGN="TOP"
+WIDTH="5%"
+><A
+NAME="FTN.AEN688"
+HREF="x675.html#AEN688"
+>[1]</A
+></TD
+><TD
+ALIGN="LEFT"
+VALIGN="TOP"
+WIDTH="95%"
+><P
+>The problem is that the subclass is
+usually not a subtype in this case because O'Caml has a contravariant subtyping
+rule. </P
+></TD
+></TR
+></TABLE
+><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="x550.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="x738.html"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>How to parse a document from an application</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="c533.html"
+>Up</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Example: An HTML backend for the <I
+CLASS="EMPHASIS"
+>readme</I
+>
+DTD</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+>
\ No newline at end of file