2 * ----------------------------------------------------------------------
3 * PXP: The polymorphic XML parser for Objective Caml.
4 * Copyright by Gerd Stolpmann. See LICENSE for details.
7 (**********************************************************************)
10 (* Object model of the document/element instances *)
12 (**********************************************************************)
15 (* ======================================================================
18 * class type node ............. The common class type of the nodes of
19 * the element tree. Nodes are either
20 * elements (inner nodes) or data nodes
22 * class type extension ........ The minimal properties of the so-called
23 * extensions of the nodes: Nodes can be
24 * customized by applying a class parameter
25 * that adds methods/values to nodes.
26 * class data_impl : node ...... Implements data nodes.
27 * class element_impl : node ... Implements element nodes
28 * class document .............. A document is an element with some additional
31 * ======================================================================
33 * THE STRUCTURE OF NODE TREES:
35 * Every node except the root node has a parent node. The parent node is
36 * always an element, because data nodes never contain other nodes.
37 * In the other direction, element nodes may have children; both elements
38 * and data nodes are possible as children.
39 * Every node knows its parent (if any) and all its children (if any);
40 * the linkage is maintained in both directions. A node without a parent
42 * It is not possible that a node is the child of two nodes (two different nodes
43 * or a multiple child of the same node).
44 * You can break the connection between a node and its parent; the method
45 * "delete" performs this operations and deletes the node from the parent's
46 * list of children. The node is now a root, for itself and for all
47 * subordinate nodes. In this context, the node is also called an orphan,
48 * because it has lost its parent (this is a bit misleading because the
49 * parent is not always the creator of a node).
50 * In order to simplify complex operations, you can also set the list of
51 * children of an element. Nodes that have been children before are unchanged;
52 * new nodes are added (and the linkage is set up), nodes no more occurring
53 * in the list are handled if they have been deleted.
54 * If you try to add a node that is not a root (either by an "add" or by a
55 * "set" operation) the operation fails.
59 * The class interface supports creation of nodes by cloning a so-called
60 * exemplar. The idea is that it is sometimes useful to implement different
61 * element types by different classes, and to implement this by looking up
63 * Imagine you have three element types A, B, and C, and three classes
64 * a, b, and c implementing the node interface (for example, by providing
65 * different extensions, see below). The XML parser can be configured to
67 * { A --> a0, B --> b0, C --> c0 }
68 * where a0, b0, c0 are exemplars of the classes a, b, and c, i.e. empty
69 * objects belonging to these classes. If the parser finds an instance of
70 * A, it looks up the exemplar a0 of A and clones it (actually, the method
71 * "create_element" performs this for elements, and "create_data" for data
72 * nodes). Clones belong to the same class as the original nodes, so the
73 * instances of the elements have the same classes as the configured
75 * Note: This technique assumes that the interface of all exemplars is the
80 * The class type node and all its implementations have a class parameter
81 * 'ext which must at least fulfil the properties of the class type "extension".
82 * The idea is that you can add properties, for example:
84 * class my_extension =
86 * (* minimal properties required by class type "extension": *)
89 * method set_node n = ...
90 * (* here my own methods: *)
91 * method do_this_and_that ...
94 * class my_element_impl = [ my_extension ] element_impl
95 * class my_data_impl = [ my_extension ] data_impl
97 * The whole XML parser is parameterized with 'ext, so your extension is
98 * visible everywhere (this is the reason why extensibility is solved by
99 * parametric polymorphism and not by inclusive polymorphism (subtyping)).
102 * SOME COMPLICATED TYPE EXPRESSIONS
104 * Sometimes the following type expressions turn out to be necessary:
106 * 'a node extension as 'a
107 * This is the type of an extension that belongs to a node that
108 * has an extension that is the same as we started with.
110 * 'a extension node as 'a
111 * This is the type of a node that has an extension that belongs to a
112 * node of the type we started with.
118 * ======================================================================
128 (* The basic and most important node types:
129 * - T_element element_type is the type of element nodes
130 * - T_data is the type of text data nodes
131 * By design of the parser, neither CDATA sections nor entity references
132 * are represented in the node tree; so there are no types for them.
137 (* The following types are extensions to my original design. They have mainly
138 * been added to simplify the implementation of standards (such as
139 * XPath) that require that nodes of these types are included into the
140 * main document tree.
141 * There are options (see Pxp_yacc) forcing the parser to insert such
142 * nodes; in this case, the nodes are actually element nodes serving
143 * as wrappers for the additional data structures. The options are:
144 * enable_super_root_node, enable_pinstr_nodes, enable_comment_nodes.
145 * By default, such nodes are not created.
148 | T_pinstr of string (* The string is the target of the PI *)
151 (* The following types are fully virtual. This means that it is impossible
152 * to make the parser insert such nodes. However, these types might be
153 * practical when defining views on the tree.
154 * Note that the list of virtual node types will be extended if necessary.
157 | T_attribute of string (* The string is the name of the attribute *)
158 | T_namespace of string (* The string is the namespace prefix *)
162 class type [ 'node ] extension =
165 (* "clone" should return an exact deep copy of the object. *)
167 (* "node" returns the corresponding node of this extension. This method
168 * intended to return exactly what previously has been set by "set_node".
170 method set_node : 'node -> unit
171 (* "set_node" is invoked once the extension is associated to a new
178 class type [ 'ext ] node =
180 constraint 'ext = 'ext node #extension
182 method extension : 'ext
183 (* Return the extension of this node: *)
186 (* Delete this node from the parent's list of sub nodes. This node gets
188 * 'delete' does nothing if this node does not have a parent.
191 method parent : 'ext node
192 (* Get the parent, or raise Not_found if this node is an orphan. *)
194 method root : 'ext node
195 (* Get the direct or indirect parent that does not have a parent itself,
196 * i.e. the root of the tree.
199 method orphaned_clone : 'self
200 (* return an exact clone of this element and all sub nodes (deep copy)
201 * except string values which are shared by this node and the clone.
202 * The other exception is that the clone has no parent (i.e. it is now
206 method orphaned_flat_clone : 'self
207 (* return a clone of this element where all subnodes are omitted.
208 * The type of the node, and the attributes are the same as in the
210 * The clone has no parent.
213 method add_node : ?force:bool -> 'ext node -> unit
214 (* Append new sub nodes -- mainly used by the parser itself, but
215 * of course open for everybody. If an element is added, it must be
216 * an orphan (i.e. does not have a parent node); and after addition
217 * *this* node is the new parent.
218 * The method performs some basic validation checks if the current node
219 * has a regular expression as content model, or is EMPTY. You can
220 * turn these checks off by passing ~force:true to the method.
223 method add_pinstr : proc_instruction -> unit
224 (* Add a processing instruction to the set of processing instructions of
225 * this node. Usually only elements contain processing instructions.
228 method pinstr : string -> proc_instruction list
229 (* Get all processing instructions with the passed name *)
231 method pinstr_names : string list
232 (* Get a list of all names of processing instructions *)
234 method node_position : int
235 (* Returns the position of this node among all children of the parent
236 * node. Positions are counted from 0.
237 * Raises Not_found if the node is the root node.
240 method node_path : int list
241 (* Returns the list of node positions of the ancestors of this node,
242 * including this node. The first list element is the node position
243 * of this child of the root, and the last list element is the
244 * node position of this node.
245 * Returns [] if the node is the root node.
248 method sub_nodes : 'ext node list
249 (* Get the list of sub nodes *)
251 method iter_nodes : ('ext node -> unit) -> unit
252 (* iterate over the sub nodes *)
254 method iter_nodes_sibl :
255 ('ext node option -> 'ext node -> 'ext node option -> unit) -> unit
256 (* Here every iteration step can also access to the previous and to the
257 * following node if present.
260 method nth_node : int -> 'ext node
261 (* Returns the n-th sub node of this node, n >= 0. Raises Not_found
262 * if the index is out of the valid range.
263 * Note that the first invocation of this method requires additional
267 method previous_node : 'ext node
268 method next_node : 'ext node
269 (* Return the previous and next nodes, respectively. These methods are
271 * - parent # nth_node (self # node_position - 1) and
272 * - parent # nth_node (self # node_position + 1), respectively.
275 method set_nodes : 'ext node list -> unit
276 (* Set the list of sub nodes. Elements that are no longer sub nodes gets
277 * orphaned, and all new elements that previously were not sub nodes
278 * must have been orphaned.
282 (* Get the data string of this node. For data nodes, this string is just
283 * the content. For elements, this string is the concatenation of all
284 * subordinate data nodes.
287 method node_type : node_type
288 (* Get the name of the element type. *)
290 method position : (string * int * int)
291 (* Return the name of the entity, the line number, and the column
292 * position (byte offset) of the beginning of the element.
293 * Only available if the element has been created with position
295 * Returns "?",0,0 if not available. (Note: Line number 0 is not
296 * possible otherwise.)
299 method attribute : string -> Pxp_types.att_value
300 method attribute_names : string list
301 method attribute_type : string -> Pxp_types.att_type
302 method attributes : (string * Pxp_types.att_value) list
303 (* Get a specific attribute; get the names of all attributes; get the
304 * type of a specific attribute; get names and values of all attributes.
305 * Only elements have attributes.
306 * Note: If the DTD allows arbitrary for this element, "attribute_type"
310 method required_string_attribute : string -> string
311 method required_list_attribute : string -> string list
312 (* Return the attribute or fail if the attribute is not present:
313 * The first version passes the value always as string back;
314 * the second version always as list.
317 method optional_string_attribute : string -> string option
318 method optional_list_attribute : string -> string list
319 (* Return some attribute value or return None if the attribute is not
321 * The first version passes the value always as string back;
322 * the second version always as list.
325 method id_attribute_name : string
326 method id_attribute_value : string
327 (* Return the name and value of the ID attribute. The methods may
328 * raise Not_found if there is no ID attribute in the DTD, or no
329 * ID attribute in the element, respectively.
332 method idref_attribute_names : string list
333 (* Returns the list of attribute names of IDREF or IDREFS type. *)
335 method quick_set_attributes : (string * Pxp_types.att_value) list -> unit
336 (* Sets the attributes but does not check whether they match the DTD.
339 method attributes_as_nodes : 'ext node list
340 (* Experimental feature: Return the attributes as node list. Every node
341 * has type T_attribute n, and contains only the single attribute n.
342 * This node list is computed on demand, so the first invocation of this
343 * method will create the list, and following invocations will only
344 * return the existing list.
347 method set_comment : string option -> unit
348 (* Sets the comment string; only applicable for T_comment nodes *)
350 method comment : string option
351 (* Get the comment string.
352 * Returns always None for nodes with a type other than T_comment.
356 (* Get the DTD. Fails if no DTD is specified (which is impossible if
357 * 'create_element' or 'create_data' have been used to create this
361 method encoding : Pxp_types.rep_encoding
362 (* Get the encoding which is always the same as the encoding of the
363 * DTD. See also method 'dtd' (Note: This method fails, too, if
364 * no DTD is present.)
367 method create_element :
368 ?position:(string * int * int) ->
369 dtd -> node_type -> (string * string) list -> 'ext node
370 (* create an "empty copy" of this element:
372 * - new node type (which must not be T_data)
373 * - new attribute list
374 * - empty list of nodes
377 method create_data : dtd -> string -> 'ext node
378 (* create an "empty copy" of this data node: *)
380 method local_validate :
383 (* Check that this element conforms to the DTD.
384 * Option ~use_dfa: If true, the deterministic finite automaton of
385 * regexp content models is used for validation, if available.
389 method keep_always_whitespace_mode : unit
390 (* Normally, add_node does not accept data nodes when the DTD does not
391 * allow data nodes or only whitespace ("ignorable whitespace").
392 * Once you have invoked this method, ignorable whitespace is forced
393 * to be included into the document.
396 method write : Pxp_types.output_stream -> Pxp_types.encoding -> unit
397 (* Write the contents of this node and the subtrees to the passed
398 * output stream; the passed encoding is used. The format
399 * is compact (the opposite of "pretty printing").
402 method write_compact_as_latin1 : Pxp_types.output_stream -> unit
403 (* DEPRECATED METHOD; included only to keep compatibility with
404 * older versions of the parser
408 (* ---------------------------------------- *)
409 (* The methods 'find' and 'reset_finder' are no longer supported.
410 * The functionality is provided by the configurable index object
415 (* ---------------------------------------- *)
416 (* internal methods: *)
417 method internal_adopt : 'ext node option -> int -> unit
418 method internal_set_pos : int -> unit
419 method internal_delete : 'ext node -> unit
420 method internal_init : (string * int * int) ->
421 dtd -> string -> (string * string) list -> unit
422 method internal_init_other : (string * int * int) ->
423 dtd -> node_type -> unit
428 class [ 'ext ] data_impl : 'ext -> [ 'ext ] node
430 * new data_impl an_extension
431 * creates a new data node with the given extension and the empty string
437 class [ 'ext ] element_impl : 'ext -> [ 'ext ] node
439 * new element_impl an_extension
440 * creates a new empty element node with the given extension.
445 (* Attribute and namespace nodes are experimental: *)
447 class [ 'ext ] attribute_impl :
448 element:string -> name:string -> Pxp_types.att_value -> dtd -> [ 'ext ] node
451 * new attribute_impl element_name attribute_name attribute_value dtd
452 * Note that attribute nodes do intentionally not have extensions.
455 (* Once namespaces get implemented:
456 class [ 'ext ] namespace_impl :
457 prefix:string -> name:string -> dtd -> [ 'ext ] node
460 (********************************** spec *********************************)
463 constraint 'ext = 'ext node #extension
464 (* Contains the exemplars used for the creation of new nodes
468 val make_spec_from_mapping :
469 ?super_root_exemplar : 'ext node ->
470 ?comment_exemplar : 'ext node ->
471 ?default_pinstr_exemplar : 'ext node ->
472 ?pinstr_mapping : (string, 'ext node) Hashtbl.t ->
473 data_exemplar: 'ext node ->
474 default_element_exemplar: 'ext node ->
475 element_mapping: (string, 'ext node) Hashtbl.t ->
479 * - For new data nodes, the ~data_exemplar must be used
480 * - For new element nodes: If the element type is mentioned in the
481 * ~element_mapping hash table, the exemplar found in this table is
482 * used. Otherwise, the ~default_element_exemplar is used.
484 * - You may also specify exemplars for super root nodes, for comments
485 * and for processing instructions
488 val make_spec_from_alist :
489 ?super_root_exemplar : 'ext node ->
490 ?comment_exemplar : 'ext node ->
491 ?default_pinstr_exemplar : 'ext node ->
492 ?pinstr_alist : (string * 'ext node) list ->
493 data_exemplar: 'ext node ->
494 default_element_exemplar: 'ext node ->
495 element_alist: (string * 'ext node) list ->
498 (* This is a convenience function: You can pass the mappings from
499 * elements and PIs to exemplar by associative lists.
502 val create_data_node :
503 'ext spec -> dtd -> string -> 'ext node
504 val create_element_node :
505 ?position:(string * int * int) ->
506 'ext spec -> dtd -> string -> (string * string) list -> 'ext node
507 val create_super_root_node :
508 ?position:(string * int * int) ->
509 'ext spec -> dtd -> 'ext node
510 val create_comment_node :
511 ?position:(string * int * int) ->
512 'ext spec -> dtd -> string -> 'ext node
513 val create_pinstr_node :
514 ?position:(string * int * int) ->
515 'ext spec -> dtd -> proc_instruction -> 'ext node
516 (* These functions use the exemplars contained in a spec and create fresh
517 * node objects from them.
521 ?position:(string * int * int) -> 'ext spec -> dtd -> 'ext node
522 (* Creates a T_none node with limited functionality *)
524 (*********************** Ordering of nodes ******************************)
526 val compare : 'ext node -> 'ext node -> int
527 (* Returns -1 if the first node is before the second node, or +1 if the
528 * first node is after the second node, or 0 if both nodes are identical.
529 * If the nodes are unrelated (do not have a common ancestor), the result
531 * This test is rather slow.
535 constraint 'ext = 'ext node #extension
536 (* The type of ordinal indexes *)
538 val create_ord_index : 'ext node -> 'ext ord_index
539 (* Creates an ordinal index for the subtree starting at the passed node.
540 * This index assigns to every node an ordinal number (beginning with 0) such
541 * that nodes are numbered upon the order of the first character in the XML
542 * representation (document order).
543 * Note that the index is not automatically updated when the tree is
547 val ord_number : 'ext ord_index -> 'ext node -> int
548 (* Returns the ordinal number of the node, or raises Not_found *)
550 val ord_compare : 'ext ord_index -> 'ext node -> 'ext node -> int
551 (* Compares two nodes like 'compare':
552 * Returns -1 if the first node is before the second node, or +1 if the
553 * first node is after the second node, or 0 if both nodes are identical.
554 * If one of the nodes does not occur in the ordinal index, Not_found
556 * This test is much faster than 'compare'.
560 (***************************** Iterators ********************************)
562 val find : ?deeply:bool ->
563 f:('ext node -> bool) -> 'ext node -> 'ext node
564 (* Searches the first node for which the predicate f is true, and returns
565 * it. Raises Not_found if there is no such node.
566 * By default, ~deeply=false. In this case, only the children of the
567 * passed node are searched.
568 * If passing ~deeply=true, the children are searched recursively
569 * (depth-first search).
572 val find_all : ?deeply:bool ->
573 f:('ext node -> bool) -> 'ext node -> 'ext node list
574 (* Searches all nodes for which the predicate f is true, and returns them.
575 * By default, ~deeply=false. In this case, only the children of the
576 * passed node are searched.
577 * If passing ~deeply=true, the children are searched recursively
578 * (depth-first search).
581 val find_element : ?deeply:bool ->
582 string -> 'ext node -> 'ext node
583 (* Searches the first element with the passed element type.
584 * By default, ~deeply=false. In this case, only the children of the
585 * passed node are searched.
586 * If passing ~deeply=true, the children are searched recursively
587 * (depth-first search).
590 val find_all_elements : ?deeply:bool ->
591 string -> 'ext node -> 'ext node list
592 (* Searches all elements with the passed element type.
593 * By default, ~deeply=false. In this case, only the children of the
594 * passed node are searched.
595 * If passing ~deeply=true, the children are searched recursively
596 * (depth-first search).
600 val map_tree : pre:('exta node -> 'extb node) ->
601 ?post:('extb node -> 'extb node) ->
604 (* Traverses the passed node and all children recursively. After entering
605 * a node, the function ~pre is called. The result of this function must
606 * be a new node; it must not have children nor a parent (you can simply
607 * pass (fun n -> n # orphaned_flat_clone) as ~pre).
608 * After that, the children are processed in the same way (from left to
609 * right); the results of the transformation will be added to the
610 * new node as new children.
611 * Now, the ~post function is invoked with this node as argument, and
612 * the result is the result of the function (~post should return a root
613 * node, too; if not specified, the identity is the ~post function).
614 * Both ~pre and ~post may raise Skip, which causes that the node is
615 * left out. If the top node is skipped, the exception Not_found is
620 pre: ('exta node option -> 'exta node -> 'exta node option ->
622 ?post:('extb node option -> 'extb node -> 'extb node option ->
626 (* Works like map_tree, but the function ~pre and ~post have additional
628 * - ~pre l n r: The node n is the node to map, and l is the previous
629 * node, and r is the next node (both None if not present). l and r
630 * are both nodes before the transformation.
631 * - ~post l n r: The node n is the node which is the result of ~pre
632 * plus adding children. l and r are again the previous and the next
633 * node, respectively, but after being transformed.
636 val iter_tree : ?pre:('ext node -> unit) ->
637 ?post:('ext node -> unit) ->
640 (* Iterates only instead of mapping the nodes. *)
643 ?pre: ('ext node option -> 'ext node -> 'ext node option -> unit) ->
644 ?post:('ext node option -> 'ext node -> 'ext node option -> unit) ->
647 (* Iterates only instead of mapping the nodes. *)
650 (******************************* document ********************************)
653 class [ 'ext ] document :
654 Pxp_types.collect_warnings ->
656 (* Documents: These are containers for root elements and for DTDs.
658 * Important invariant: A document is either empty (no root element,
659 * no DTD), or it has both a root element and a DTD.
661 * A fresh document created by 'new' is empty.
664 method init_xml_version : string -> unit
665 (* Set the XML version string of the XML declaration. *)
667 method init_root : 'ext node -> unit
668 (* Set the root element. It is expected that the root element has
670 * Note that 'init_root' checks whether the passed root element
671 * has the type expected by the DTD. The check takes into account
672 * that the root element might be a virtual root node.
675 method xml_version : string
676 (* Returns the XML version from the XML declaration. Returns "1.0"
677 * if the declaration is missing.
680 method xml_standalone : bool
681 (* Returns whether this document is declared as being standalone.
682 * This method returns the same value as 'standalone_declaration'
683 * of the DTD (if there is a DTD).
684 * Returns 'false' if there is no DTD.
688 (* Returns the DTD of the root element.
689 * Fails if there is no root element.
692 method encoding : Pxp_types.rep_encoding
693 (* Returns the string encoding of the document = the encoding of
694 * the root element = the encoding of the element tree = the
695 * encoding of the DTD.
696 * Fails if there is no root element.
699 method root : 'ext node
700 (* Returns the root element, or fails if there is not any. *)
702 method add_pinstr : proc_instruction -> unit
703 (* Adds a processing instruction to the document container.
704 * The parser does this for PIs occurring outside the DTD and outside
708 method pinstr : string -> proc_instruction list
709 (* Return all PIs for a passed target string. *)
711 method pinstr_names : string list
712 (* Return all target strings of all PIs. *)
714 method write : Pxp_types.output_stream -> Pxp_types.encoding -> unit
715 (* Write the document to the passed
716 * output stream; the passed encoding used. The format
717 * is compact (the opposite of "pretty printing").
718 * If a DTD is present, the DTD is included into the internal subset.
721 method write_compact_as_latin1 : Pxp_types.output_stream -> unit
722 (* DEPRECATED METHOD; included only to keep compatibility with
723 * older versions of the parser
730 (* ======================================================================
734 * Revision 1.1 2000/11/17 09:57:29 lpadovan
737 * Revision 1.10 2000/08/30 15:47:37 gerd
738 * New method node_path.
739 * New function compare.
740 * New type ord_index with functions.
742 * Revision 1.9 2000/08/26 23:27:53 gerd
743 * New function: make_spec_from_alist.
744 * New iterators: find, find_all, find_element, find_all_elements,
745 * map_tree, map_tree_sibl, iter_tree, iter_tree_sibl.
746 * New node methods: node_position, nth_node, previous_node,
748 * Attribute and namespace types have now a string argument:
749 * the name/prefix. I hope this simplifies the handling of view nodes.
750 * First implementation of view nodes: attribute_impl. The
751 * method attributes_as_nodes returns the attributes wrapped into
752 * T_attribute nodes which reside outside the document tree.
754 * Revision 1.8 2000/08/18 20:14:00 gerd
755 * New node_types: T_super_root, T_pinstr, T_comment, (T_attribute),
756 * (T_none), (T_namespace).
758 * Revision 1.7 2000/07/23 02:16:34 gerd
761 * Revision 1.6 2000/07/16 16:34:41 gerd
762 * New method 'write', the successor of 'write_compact_as_latin1'.
764 * Revision 1.5 2000/07/14 13:56:11 gerd
765 * Added methods id_attribute_name, id_attribute_value,
766 * idref_attribute_names.
768 * Revision 1.4 2000/07/09 17:51:14 gerd
769 * Element nodes can store positions.
771 * Revision 1.3 2000/07/04 22:05:10 gerd
772 * New functions make_spec_from_mapping, create_data_node,
773 * create_element_node.
775 * Revision 1.2 2000/06/14 22:19:06 gerd
776 * Added checks such that it is impossible to mix encodings.
778 * Revision 1.1 2000/05/29 23:48:38 gerd
779 * Changed module names:
780 * Markup_aux into Pxp_aux
781 * Markup_codewriter into Pxp_codewriter
782 * Markup_document into Pxp_document
783 * Markup_dtd into Pxp_dtd
784 * Markup_entity into Pxp_entity
785 * Markup_lexer_types into Pxp_lexer_types
786 * Markup_reader into Pxp_reader
787 * Markup_types into Pxp_types
788 * Markup_yacc into Pxp_yacc
789 * See directory "compatibility" for (almost) compatible wrappers emulating
790 * Markup_document, Markup_dtd, Markup_reader, Markup_types, and Markup_yacc.
792 * ======================================================================
793 * Old logs from markup_document.mli:
795 * Revision 1.13 2000/05/27 19:15:08 gerd
796 * Removed the method init_xml_standalone.
798 * Revision 1.12 2000/05/01 20:42:34 gerd
799 * New method write_compact_as_latin1.
801 * Revision 1.11 2000/04/30 18:15:57 gerd
803 * New method keep_always_whitespace_mode.
805 * Revision 1.10 2000/03/11 22:58:15 gerd
806 * Updated to support Markup_codewriter.
808 * Revision 1.9 2000/01/27 21:51:56 gerd
809 * Added method 'attributes'.
811 * Revision 1.8 2000/01/27 21:19:07 gerd
812 * Added further methods.
814 * Revision 1.7 1999/11/09 22:20:14 gerd
815 * Removed method init_dtd from class "document". The DTD is
816 * implicitly passed to the document by the root element.
818 * Revision 1.6 1999/09/01 22:51:40 gerd
819 * Added methods to store processing instructions.
821 * Revision 1.5 1999/09/01 16:19:57 gerd
822 * The "document" class has now a "warner" as class argument.
824 * Revision 1.4 1999/08/19 21:59:13 gerd
825 * Added method "reset_finder".
827 * Revision 1.3 1999/08/19 01:08:29 gerd
828 * Added method "find".
830 * Revision 1.2 1999/08/15 02:19:41 gerd
831 * Some new explanations: That unknown elements are not rejected
832 * if the DTD allows them.
834 * Revision 1.1 1999/08/10 00:35:51 gerd