pxp-1.2.9/0000755000175000017500000000000013055274560010765 5ustar gerdgerdpxp-1.2.9/LICENSE0000644000175000017500000000207213055274551011773 0ustar gerdgerdCopyright 1999-2009 by Gerd Stolpmann The package PXP is copyright by Gerd Stolpmann. Permission is hereby granted, free of charge, to any person obtaining a copy of this document and the PXP software (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The Software is provided ``as is'', without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall Gerd Stolpmann be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the software. pxp-1.2.9/Makefile0000644000175000017500000000442413055274551012431 0ustar gerdgerd# make all: compiles the configured packages with ocamlc # make opt: compiles the configured packages with ocamlopt # make install: installs the configured packages # make clean: cleans everything up NAME=pxp TOP_DIR=. include Makefile.rules .PHONY: build build: all if ocamlopt 2>/dev/null; then $(MAKE) opt; fi .PHONY: all all: $(MAKE) -C tools all for pkg in $(PKGLIST); do $(MAKE) -C src/$$pkg all || exit; done for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg clean || exit; done for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg generate || exit; done for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg all || exit; done .PHONY: opt opt: for pkg in $(PKGLIST); do $(MAKE) -C src/$$pkg opt || exit; done for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg opt || exit; done # The following are for development: .PHONY: lexers lexers: for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg generate || exit; done for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg all || exit; done .PHONY: lexers-again lexers-again: for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg clean || exit; done $(MAKE) lexers # The following PHONY rule is important for Cygwin: .PHONY: install install: for pkg in $(PKGLIST); do $(MAKE) -C src/$$pkg install || exit; done for pkg in $(GENPKGLIST); do $(MAKE) -C gensrc/$$pkg install || exit; done .PHONY: uninstall uninstall: $(MAKE) -C src uninstall for pkg in $(ALLGENPKGLIST); do $(OCAMLFIND) remove $$pkg; done # On the toplevel, clean is CLEAN: .PHONY: clean clean: $(MAKE) -C tools CLEAN $(MAKE) -C src CLEAN for dir in gensrc/pxp-*; do $(MAKE) -C $$dir CLEAN || true; done $(MAKE) -C examples CLEAN $(MAKE) -C rtests CLEAN rm -f .testscript .testout .PHONY: CLEAN CLEAN: clean .PHONY: distclean distclean: rm -f *~ Makefile.conf $(MAKE) -C tools distclean $(MAKE) -C src distclean $(MAKE) -C examples distclean $(MAKE) -C rtests distclean test ! -f doc/Makefile || $(MAKE) -C doc distclean for dir in gensrc/pxp-*; do if [ -f $$dir/gen_dir ]; then rm -rf $$dir; else $(MAKE) -C $$dir distclean; fi; done .PHONY: RELEASE RELEASE: ./configure -version >RELEASE # for oasis .PHONY: _oasis _oasis: _oasis.in sed -e 's/@VERSION@/$(VERSION)/' _oasis.in >_oasis oasis setup .PHONY: postconf postconf: cat setup.save >>setup.data pxp-1.2.9/Makefile.rules0000644000175000017500000000171513055274551013562 0ustar gerdgerd# Inclusion of Makefile.conf may fail when cleaning up: -include $(TOP_DIR)/Makefile.conf # How to invoke compilers and tools: OCAMLC = $(OCAMLFIND) ocamlc -g $(STRING_OPTS) $(OCAMLC_OPTIONS) -package "$(PACKAGES)" OCAMLOPT = $(OCAMLFIND) ocamlopt $(STRING_OPTS) $(OCAMLOPT_OPTIONS) -package "$(PACKAGES)" OCAMLDEP = ocamldep $(OCAMLDEP_OPTIONS) OCAMLFIND = ocamlfind OCAMLYACC = ocamlyacc OCAMLLEX = ocamllex$(LEX_OPT) WLEX = wlex TOOLS_DIR = $(TOP_DIR)/tools M2PARSERGEN = $(TOOLS_DIR)/m2parsergen LEXPP = $(TOOLS_DIR)/lexpp COLLECT_FILES = $(TOOLS_DIR)/collect_files IFDEF = $(TOOLS_DIR)/ifdef # Files to remove everywhere by "make clean": CLEAN_LIST = *.cmi *.cmo *.cma *.cmx *.o *.a *.cmxa # Generic build rules: .SUFFIXES: .cmo .cmi .cmx .ml .mli .mll .mly .m2y .ml.cmx: $(OCAMLOPT) -c $< .ml.cmo: $(OCAMLC) -c $< .mli.cmi: $(OCAMLC) -c $< .mll.ml: $(OCAMLLEX) $< .mly.ml: $(OCAMLYACC) $< .m2y.ml: $(M2PARSERGEN) $< pxp-1.2.9/setup.ml0000644000175000017500000114237713055274551012476 0ustar gerdgerd(* setup.ml generated for the first time by OASIS v0.4.4 *) (* OASIS_START *) (* DO NOT EDIT (digest: c3fa950038b202897f5d1273efe3675f) *) (* Regenerated by OASIS v0.4.8 Visit http://oasis.forge.ocamlcore.org for more information and documentation about functions used in this file. *) module OASISGettext = struct (* # 22 "src/oasis/OASISGettext.ml" *) let ns_ str = str let s_ str = str let f_ (str: ('a, 'b, 'c, 'd) format4) = str let fn_ fmt1 fmt2 n = if n = 1 then fmt1^^"" else fmt2^^"" let init = [] end module OASISString = struct (* # 22 "src/oasis/OASISString.ml" *) (** Various string utilities. Mostly inspired by extlib and batteries ExtString and BatString libraries. @author Sylvain Le Gall *) let nsplitf str f = if str = "" then [] else let buf = Buffer.create 13 in let lst = ref [] in let push () = lst := Buffer.contents buf :: !lst; Buffer.clear buf in let str_len = String.length str in for i = 0 to str_len - 1 do if f str.[i] then push () else Buffer.add_char buf str.[i] done; push (); List.rev !lst (** [nsplit c s] Split the string [s] at char [c]. It doesn't include the separator. *) let nsplit str c = nsplitf str ((=) c) let find ~what ?(offset=0) str = let what_idx = ref 0 in let str_idx = ref offset in while !str_idx < String.length str && !what_idx < String.length what do if str.[!str_idx] = what.[!what_idx] then incr what_idx else what_idx := 0; incr str_idx done; if !what_idx <> String.length what then raise Not_found else !str_idx - !what_idx let sub_start str len = let str_len = String.length str in if len >= str_len then "" else String.sub str len (str_len - len) let sub_end ?(offset=0) str len = let str_len = String.length str in if len >= str_len then "" else String.sub str 0 (str_len - len) let starts_with ~what ?(offset=0) str = let what_idx = ref 0 in let str_idx = ref offset in let ok = ref true in while !ok && !str_idx < String.length str && !what_idx < String.length what do if str.[!str_idx] = what.[!what_idx] then incr what_idx else ok := false; incr str_idx done; if !what_idx = String.length what then true else false let strip_starts_with ~what str = if starts_with ~what str then sub_start str (String.length what) else raise Not_found let ends_with ~what ?(offset=0) str = let what_idx = ref ((String.length what) - 1) in let str_idx = ref ((String.length str) - 1) in let ok = ref true in while !ok && offset <= !str_idx && 0 <= !what_idx do if str.[!str_idx] = what.[!what_idx] then decr what_idx else ok := false; decr str_idx done; if !what_idx = -1 then true else false let strip_ends_with ~what str = if ends_with ~what str then sub_end str (String.length what) else raise Not_found let replace_chars f s = let buf = Buffer.create (String.length s) in String.iter (fun c -> Buffer.add_char buf (f c)) s; Buffer.contents buf let lowercase_ascii = replace_chars (fun c -> if (c >= 'A' && c <= 'Z') then Char.chr (Char.code c + 32) else c) let uncapitalize_ascii s = if s <> "" then (lowercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1)) else s let uppercase_ascii = replace_chars (fun c -> if (c >= 'a' && c <= 'z') then Char.chr (Char.code c - 32) else c) let capitalize_ascii s = if s <> "" then (uppercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1)) else s end module OASISUtils = struct (* # 22 "src/oasis/OASISUtils.ml" *) open OASISGettext module MapExt = struct module type S = sig include Map.S val add_list: 'a t -> (key * 'a) list -> 'a t val of_list: (key * 'a) list -> 'a t val to_list: 'a t -> (key * 'a) list end module Make (Ord: Map.OrderedType) = struct include Map.Make(Ord) let rec add_list t = function | (k, v) :: tl -> add_list (add k v t) tl | [] -> t let of_list lst = add_list empty lst let to_list t = fold (fun k v acc -> (k, v) :: acc) t [] end end module MapString = MapExt.Make(String) module SetExt = struct module type S = sig include Set.S val add_list: t -> elt list -> t val of_list: elt list -> t val to_list: t -> elt list end module Make (Ord: Set.OrderedType) = struct include Set.Make(Ord) let rec add_list t = function | e :: tl -> add_list (add e t) tl | [] -> t let of_list lst = add_list empty lst let to_list = elements end end module SetString = SetExt.Make(String) let compare_csl s1 s2 = String.compare (OASISString.lowercase_ascii s1) (OASISString.lowercase_ascii s2) module HashStringCsl = Hashtbl.Make (struct type t = string let equal s1 s2 = (compare_csl s1 s2) = 0 let hash s = Hashtbl.hash (OASISString.lowercase_ascii s) end) module SetStringCsl = SetExt.Make (struct type t = string let compare = compare_csl end) let varname_of_string ?(hyphen='_') s = if String.length s = 0 then begin invalid_arg "varname_of_string" end else begin let buf = OASISString.replace_chars (fun c -> if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') then c else hyphen) s; in let buf = (* Start with a _ if digit *) if '0' <= s.[0] && s.[0] <= '9' then "_"^buf else buf in OASISString.lowercase_ascii buf end let varname_concat ?(hyphen='_') p s = let what = String.make 1 hyphen in let p = try OASISString.strip_ends_with ~what p with Not_found -> p in let s = try OASISString.strip_starts_with ~what s with Not_found -> s in p^what^s let is_varname str = str = varname_of_string str let failwithf fmt = Printf.ksprintf failwith fmt let rec file_location ?pos1 ?pos2 ?lexbuf () = match pos1, pos2, lexbuf with | Some p, None, _ | None, Some p, _ -> file_location ~pos1:p ~pos2:p ?lexbuf () | Some p1, Some p2, _ -> let open Lexing in let fn, lineno = p1.pos_fname, p1.pos_lnum in let c1 = p1.pos_cnum - p1.pos_bol in let c2 = c1 + (p2.pos_cnum - p1.pos_cnum) in Printf.sprintf (f_ "file %S, line %d, characters %d-%d") fn lineno c1 c2 | _, _, Some lexbuf -> file_location ~pos1:(Lexing.lexeme_start_p lexbuf) ~pos2:(Lexing.lexeme_end_p lexbuf) () | None, None, None -> s_ "" let failwithpf ?pos1 ?pos2 ?lexbuf fmt = let loc = file_location ?pos1 ?pos2 ?lexbuf () in Printf.ksprintf (fun s -> failwith (Printf.sprintf "%s: %s" loc s)) fmt end module OASISUnixPath = struct (* # 22 "src/oasis/OASISUnixPath.ml" *) type unix_filename = string type unix_dirname = string type host_filename = string type host_dirname = string let current_dir_name = "." let parent_dir_name = ".." let is_current_dir fn = fn = current_dir_name || fn = "" let concat f1 f2 = if is_current_dir f1 then f2 else let f1' = try OASISString.strip_ends_with ~what:"/" f1 with Not_found -> f1 in f1'^"/"^f2 let make = function | hd :: tl -> List.fold_left (fun f p -> concat f p) hd tl | [] -> invalid_arg "OASISUnixPath.make" let dirname f = try String.sub f 0 (String.rindex f '/') with Not_found -> current_dir_name let basename f = try let pos_start = (String.rindex f '/') + 1 in String.sub f pos_start ((String.length f) - pos_start) with Not_found -> f let chop_extension f = try let last_dot = String.rindex f '.' in let sub = String.sub f 0 last_dot in try let last_slash = String.rindex f '/' in if last_slash < last_dot then sub else f with Not_found -> sub with Not_found -> f let capitalize_file f = let dir = dirname f in let base = basename f in concat dir (OASISString.capitalize_ascii base) let uncapitalize_file f = let dir = dirname f in let base = basename f in concat dir (OASISString.uncapitalize_ascii base) end module OASISHostPath = struct (* # 22 "src/oasis/OASISHostPath.ml" *) open Filename open OASISGettext module Unix = OASISUnixPath let make = function | [] -> invalid_arg "OASISHostPath.make" | hd :: tl -> List.fold_left Filename.concat hd tl let of_unix ufn = match Sys.os_type with | "Unix" | "Cygwin" -> ufn | "Win32" -> make (List.map (fun p -> if p = Unix.current_dir_name then current_dir_name else if p = Unix.parent_dir_name then parent_dir_name else p) (OASISString.nsplit ufn '/')) | os_type -> OASISUtils.failwithf (f_ "Don't know the path format of os_type %S when translating unix \ filename. %S") os_type ufn end module OASISFileSystem = struct (* # 22 "src/oasis/OASISFileSystem.ml" *) (** File System functions @author Sylvain Le Gall *) type 'a filename = string class type closer = object method close: unit end class type reader = object inherit closer method input: Buffer.t -> int -> unit end class type writer = object inherit closer method output: Buffer.t -> unit end class type ['a] fs = object method string_of_filename: 'a filename -> string method open_out: ?mode:(open_flag list) -> ?perm:int -> 'a filename -> writer method open_in: ?mode:(open_flag list) -> ?perm:int -> 'a filename -> reader method file_exists: 'a filename -> bool method remove: 'a filename -> unit end module Mode = struct let default_in = [Open_rdonly] let default_out = [Open_wronly; Open_creat; Open_trunc] let text_in = Open_text :: default_in let text_out = Open_text :: default_out let binary_in = Open_binary :: default_in let binary_out = Open_binary :: default_out end let std_length = 4096 (* Standard buffer/read length. *) let binary_out = Mode.binary_out let binary_in = Mode.binary_in let of_unix_filename ufn = (ufn: 'a filename) let to_unix_filename fn = (fn: string) let defer_close o f = try let r = f o in o#close; r with e -> o#close; raise e let stream_of_reader rdr = let buf = Buffer.create std_length in let pos = ref 0 in let eof = ref false in let rec next idx = let bpos = idx - !pos in if !eof then begin None end else if bpos < Buffer.length buf then begin Some (Buffer.nth buf bpos) end else begin pos := !pos + Buffer.length buf; Buffer.clear buf; begin try rdr#input buf std_length; with End_of_file -> if Buffer.length buf = 0 then eof := true end; next idx end in Stream.from next let read_all buf rdr = try while true do rdr#input buf std_length done with End_of_file -> () class ['a] host_fs rootdir : ['a] fs = object (self) method private host_filename fn = Filename.concat rootdir fn method string_of_filename = self#host_filename method open_out ?(mode=Mode.text_out) ?(perm=0o666) fn = let chn = open_out_gen mode perm (self#host_filename fn) in object method close = close_out chn method output buf = Buffer.output_buffer chn buf end method open_in ?(mode=Mode.text_in) ?(perm=0o666) fn = (* TODO: use Buffer.add_channel when minimal version of OCaml will * be >= 4.03.0 (previous version was discarding last chars). *) let chn = open_in_gen mode perm (self#host_filename fn) in let strm = Stream.of_channel chn in object method close = close_in chn method input buf len = let read = ref 0 in try for _i = 0 to len do Buffer.add_char buf (Stream.next strm); incr read done with Stream.Failure -> if !read = 0 then raise End_of_file end method file_exists fn = Sys.file_exists (self#host_filename fn) method remove fn = Sys.remove (self#host_filename fn) end end module OASISContext = struct (* # 22 "src/oasis/OASISContext.ml" *) open OASISGettext type level = [ `Debug | `Info | `Warning | `Error] type source type source_filename = source OASISFileSystem.filename let in_srcdir ufn = OASISFileSystem.of_unix_filename ufn type t = { (* TODO: replace this by a proplist. *) quiet: bool; info: bool; debug: bool; ignore_plugins: bool; ignore_unknown_fields: bool; printf: level -> string -> unit; srcfs: source OASISFileSystem.fs; load_oasis_plugin: string -> bool; } let printf lvl str = let beg = match lvl with | `Error -> s_ "E: " | `Warning -> s_ "W: " | `Info -> s_ "I: " | `Debug -> s_ "D: " in prerr_endline (beg^str) let default = ref { quiet = false; info = false; debug = false; ignore_plugins = false; ignore_unknown_fields = false; printf = printf; srcfs = new OASISFileSystem.host_fs(Sys.getcwd ()); load_oasis_plugin = (fun _ -> false); } let quiet = {!default with quiet = true} let fspecs () = (* TODO: don't act on default. *) let ignore_plugins = ref false in ["-quiet", Arg.Unit (fun () -> default := {!default with quiet = true}), s_ " Run quietly"; "-info", Arg.Unit (fun () -> default := {!default with info = true}), s_ " Display information message"; "-debug", Arg.Unit (fun () -> default := {!default with debug = true}), s_ " Output debug message"; "-ignore-plugins", Arg.Set ignore_plugins, s_ " Ignore plugin's field."; "-C", Arg.String (fun str -> Sys.chdir str; default := {!default with srcfs = new OASISFileSystem.host_fs str}), s_ "dir Change directory before running (affects setup.{data,log})."], fun () -> {!default with ignore_plugins = !ignore_plugins} end module PropList = struct (* # 22 "src/oasis/PropList.ml" *) open OASISGettext type name = string exception Not_set of name * string option exception No_printer of name exception Unknown_field of name * name let () = Printexc.register_printer (function | Not_set (nm, Some rsn) -> Some (Printf.sprintf (f_ "Field '%s' is not set: %s") nm rsn) | Not_set (nm, None) -> Some (Printf.sprintf (f_ "Field '%s' is not set") nm) | No_printer nm -> Some (Printf.sprintf (f_ "No default printer for value %s") nm) | Unknown_field (nm, schm) -> Some (Printf.sprintf (f_ "Field %s is not defined in schema %s") nm schm) | _ -> None) module Data = struct type t = (name, unit -> unit) Hashtbl.t let create () = Hashtbl.create 13 let clear t = Hashtbl.clear t (* # 77 "src/oasis/PropList.ml" *) end module Schema = struct type ('ctxt, 'extra) value = { get: Data.t -> string; set: Data.t -> ?context:'ctxt -> string -> unit; help: (unit -> string) option; extra: 'extra; } type ('ctxt, 'extra) t = { name: name; fields: (name, ('ctxt, 'extra) value) Hashtbl.t; order: name Queue.t; name_norm: string -> string; } let create ?(case_insensitive=false) nm = { name = nm; fields = Hashtbl.create 13; order = Queue.create (); name_norm = (if case_insensitive then OASISString.lowercase_ascii else fun s -> s); } let add t nm set get extra help = let key = t.name_norm nm in if Hashtbl.mem t.fields key then failwith (Printf.sprintf (f_ "Field '%s' is already defined in schema '%s'") nm t.name); Hashtbl.add t.fields key { set = set; get = get; help = help; extra = extra; }; Queue.add nm t.order let mem t nm = Hashtbl.mem t.fields nm let find t nm = try Hashtbl.find t.fields (t.name_norm nm) with Not_found -> raise (Unknown_field (nm, t.name)) let get t data nm = (find t nm).get data let set t data nm ?context x = (find t nm).set data ?context x let fold f acc t = Queue.fold (fun acc k -> let v = find t k in f acc k v.extra v.help) acc t.order let iter f t = fold (fun () -> f) () t let name t = t.name end module Field = struct type ('ctxt, 'value, 'extra) t = { set: Data.t -> ?context:'ctxt -> 'value -> unit; get: Data.t -> 'value; sets: Data.t -> ?context:'ctxt -> string -> unit; gets: Data.t -> string; help: (unit -> string) option; extra: 'extra; } let new_id = let last_id = ref 0 in fun () -> incr last_id; !last_id let create ?schema ?name ?parse ?print ?default ?update ?help extra = (* Default value container *) let v = ref None in (* If name is not given, create unique one *) let nm = match name with | Some s -> s | None -> Printf.sprintf "_anon_%d" (new_id ()) in (* Last chance to get a value: the default *) let default () = match default with | Some d -> d | None -> raise (Not_set (nm, Some (s_ "no default value"))) in (* Get data *) let get data = (* Get value *) try (Hashtbl.find data nm) (); match !v with | Some x -> x | None -> default () with Not_found -> default () in (* Set data *) let set data ?context x = let x = match update with | Some f -> begin try f ?context (get data) x with Not_set _ -> x end | None -> x in Hashtbl.replace data nm (fun () -> v := Some x) in (* Parse string value, if possible *) let parse = match parse with | Some f -> f | None -> fun ?context s -> failwith (Printf.sprintf (f_ "Cannot parse field '%s' when setting value %S") nm s) in (* Set data, from string *) let sets data ?context s = set ?context data (parse ?context s) in (* Output value as string, if possible *) let print = match print with | Some f -> f | None -> fun _ -> raise (No_printer nm) in (* Get data, as a string *) let gets data = print (get data) in begin match schema with | Some t -> Schema.add t nm sets gets extra help | None -> () end; { set = set; get = get; sets = sets; gets = gets; help = help; extra = extra; } let fset data t ?context x = t.set data ?context x let fget data t = t.get data let fsets data t ?context s = t.sets data ?context s let fgets data t = t.gets data end module FieldRO = struct let create ?schema ?name ?parse ?print ?default ?update ?help extra = let fld = Field.create ?schema ?name ?parse ?print ?default ?update ?help extra in fun data -> Field.fget data fld end end module OASISMessage = struct (* # 22 "src/oasis/OASISMessage.ml" *) open OASISGettext open OASISContext let generic_message ~ctxt lvl fmt = let cond = if ctxt.quiet then false else match lvl with | `Debug -> ctxt.debug | `Info -> ctxt.info | _ -> true in Printf.ksprintf (fun str -> if cond then begin ctxt.printf lvl str end) fmt let debug ~ctxt fmt = generic_message ~ctxt `Debug fmt let info ~ctxt fmt = generic_message ~ctxt `Info fmt let warning ~ctxt fmt = generic_message ~ctxt `Warning fmt let error ~ctxt fmt = generic_message ~ctxt `Error fmt end module OASISVersion = struct (* # 22 "src/oasis/OASISVersion.ml" *) open OASISGettext type t = string type comparator = | VGreater of t | VGreaterEqual of t | VEqual of t | VLesser of t | VLesserEqual of t | VOr of comparator * comparator | VAnd of comparator * comparator (* Range of allowed characters *) let is_digit c = '0' <= c && c <= '9' let is_alpha c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') let is_special = function | '.' | '+' | '-' | '~' -> true | _ -> false let rec version_compare v1 v2 = if v1 <> "" || v2 <> "" then begin (* Compare ascii string, using special meaning for version * related char *) let val_ascii c = if c = '~' then -1 else if is_digit c then 0 else if c = '\000' then 0 else if is_alpha c then Char.code c else (Char.code c) + 256 in let len1 = String.length v1 in let len2 = String.length v2 in let p = ref 0 in (** Compare ascii part *) let compare_vascii () = let cmp = ref 0 in while !cmp = 0 && !p < len1 && !p < len2 && not (is_digit v1.[!p] && is_digit v2.[!p]) do cmp := (val_ascii v1.[!p]) - (val_ascii v2.[!p]); incr p done; if !cmp = 0 && !p < len1 && !p = len2 then val_ascii v1.[!p] else if !cmp = 0 && !p = len1 && !p < len2 then - (val_ascii v2.[!p]) else !cmp in (** Compare digit part *) let compare_digit () = let extract_int v p = let start_p = !p in while !p < String.length v && is_digit v.[!p] do incr p done; let substr = String.sub v !p ((String.length v) - !p) in let res = match String.sub v start_p (!p - start_p) with | "" -> 0 | s -> int_of_string s in res, substr in let i1, tl1 = extract_int v1 (ref !p) in let i2, tl2 = extract_int v2 (ref !p) in i1 - i2, tl1, tl2 in match compare_vascii () with | 0 -> begin match compare_digit () with | 0, tl1, tl2 -> if tl1 <> "" && is_digit tl1.[0] then 1 else if tl2 <> "" && is_digit tl2.[0] then -1 else version_compare tl1 tl2 | n, _, _ -> n end | n -> n end else begin 0 end let version_of_string str = str let string_of_version t = t let chop t = try let pos = String.rindex t '.' in String.sub t 0 pos with Not_found -> t let rec comparator_apply v op = match op with | VGreater cv -> (version_compare v cv) > 0 | VGreaterEqual cv -> (version_compare v cv) >= 0 | VLesser cv -> (version_compare v cv) < 0 | VLesserEqual cv -> (version_compare v cv) <= 0 | VEqual cv -> (version_compare v cv) = 0 | VOr (op1, op2) -> (comparator_apply v op1) || (comparator_apply v op2) | VAnd (op1, op2) -> (comparator_apply v op1) && (comparator_apply v op2) let rec string_of_comparator = function | VGreater v -> "> "^(string_of_version v) | VEqual v -> "= "^(string_of_version v) | VLesser v -> "< "^(string_of_version v) | VGreaterEqual v -> ">= "^(string_of_version v) | VLesserEqual v -> "<= "^(string_of_version v) | VOr (c1, c2) -> (string_of_comparator c1)^" || "^(string_of_comparator c2) | VAnd (c1, c2) -> (string_of_comparator c1)^" && "^(string_of_comparator c2) let rec varname_of_comparator = let concat p v = OASISUtils.varname_concat p (OASISUtils.varname_of_string (string_of_version v)) in function | VGreater v -> concat "gt" v | VLesser v -> concat "lt" v | VEqual v -> concat "eq" v | VGreaterEqual v -> concat "ge" v | VLesserEqual v -> concat "le" v | VOr (c1, c2) -> (varname_of_comparator c1)^"_or_"^(varname_of_comparator c2) | VAnd (c1, c2) -> (varname_of_comparator c1)^"_and_"^(varname_of_comparator c2) end module OASISLicense = struct (* # 22 "src/oasis/OASISLicense.ml" *) (** License for _oasis fields @author Sylvain Le Gall *) type license = string type license_exception = string type license_version = | Version of OASISVersion.t | VersionOrLater of OASISVersion.t | NoVersion type license_dep_5_unit = { license: license; excption: license_exception option; version: license_version; } type license_dep_5 = | DEP5Unit of license_dep_5_unit | DEP5Or of license_dep_5 list | DEP5And of license_dep_5 list type t = | DEP5License of license_dep_5 | OtherLicense of string (* URL *) end module OASISExpr = struct (* # 22 "src/oasis/OASISExpr.ml" *) open OASISGettext open OASISUtils type test = string type flag = string type t = | EBool of bool | ENot of t | EAnd of t * t | EOr of t * t | EFlag of flag | ETest of test * string type 'a choices = (t * 'a) list let eval var_get t = let rec eval' = function | EBool b -> b | ENot e -> not (eval' e) | EAnd (e1, e2) -> (eval' e1) && (eval' e2) | EOr (e1, e2) -> (eval' e1) || (eval' e2) | EFlag nm -> let v = var_get nm in assert(v = "true" || v = "false"); (v = "true") | ETest (nm, vl) -> let v = var_get nm in (v = vl) in eval' t let choose ?printer ?name var_get lst = let rec choose_aux = function | (cond, vl) :: tl -> if eval var_get cond then vl else choose_aux tl | [] -> let str_lst = if lst = [] then s_ "" else String.concat (s_ ", ") (List.map (fun (cond, vl) -> match printer with | Some p -> p vl | None -> s_ "") lst) in match name with | Some nm -> failwith (Printf.sprintf (f_ "No result for the choice list '%s': %s") nm str_lst) | None -> failwith (Printf.sprintf (f_ "No result for a choice list: %s") str_lst) in choose_aux (List.rev lst) end module OASISText = struct (* # 22 "src/oasis/OASISText.ml" *) type elt = | Para of string | Verbatim of string | BlankLine type t = elt list end module OASISSourcePatterns = struct (* # 22 "src/oasis/OASISSourcePatterns.ml" *) open OASISUtils open OASISGettext module Templater = struct (* TODO: use this module in BaseEnv.var_expand and BaseFileAB, at least. *) type t = { atoms: atom list; origin: string } and atom = | Text of string | Expr of expr and expr = | Ident of string | String of string | Call of string * expr type env = { variables: string MapString.t; functions: (string -> string) MapString.t; } let eval env t = let rec eval_expr env = function | String str -> str | Ident nm -> begin try MapString.find nm env.variables with Not_found -> (* TODO: add error location within the string. *) failwithf (f_ "Unable to find variable %S in source pattern %S") nm t.origin end | Call (fn, expr) -> begin try (MapString.find fn env.functions) (eval_expr env expr) with Not_found -> (* TODO: add error location within the string. *) failwithf (f_ "Unable to find function %S in source pattern %S") fn t.origin end in String.concat "" (List.map (function | Text str -> str | Expr expr -> eval_expr env expr) t.atoms) let parse env s = let lxr = Genlex.make_lexer [] in let parse_expr s = let st = lxr (Stream.of_string s) in match Stream.npeek 3 st with | [Genlex.Ident fn; Genlex.Ident nm] -> Call(fn, Ident nm) | [Genlex.Ident fn; Genlex.String str] -> Call(fn, String str) | [Genlex.String str] -> String str | [Genlex.Ident nm] -> Ident nm (* TODO: add error location within the string. *) | _ -> failwithf (f_ "Unable to parse expression %S") s in let parse s = let lst_exprs = ref [] in let ss = let buff = Buffer.create (String.length s) in Buffer.add_substitute buff (fun s -> lst_exprs := (parse_expr s) :: !lst_exprs; "\000") s; Buffer.contents buff in let rec join = function | hd1 :: tl1, hd2 :: tl2 -> Text hd1 :: Expr hd2 :: join (tl1, tl2) | [], tl -> List.map (fun e -> Expr e) tl | tl, [] -> List.map (fun e -> Text e) tl in join (OASISString.nsplit ss '\000', List.rev (!lst_exprs)) in let t = {atoms = parse s; origin = s} in (* We rely on a simple evaluation for checking variables/functions. It works because there is no if/loop statement. *) let _s : string = eval env t in t (* # 144 "src/oasis/OASISSourcePatterns.ml" *) end type t = Templater.t let env ~modul () = { Templater. variables = MapString.of_list ["module", modul]; functions = MapString.of_list [ "capitalize_file", OASISUnixPath.capitalize_file; "uncapitalize_file", OASISUnixPath.uncapitalize_file; ]; } let all_possible_files lst ~path ~modul = let eval = Templater.eval (env ~modul ()) in List.fold_left (fun acc pat -> OASISUnixPath.concat path (eval pat) :: acc) [] lst let to_string t = t.Templater.origin end module OASISTypes = struct (* # 22 "src/oasis/OASISTypes.ml" *) type name = string type package_name = string type url = string type unix_dirname = string type unix_filename = string (* TODO: replace everywhere. *) type host_dirname = string (* TODO: replace everywhere. *) type host_filename = string (* TODO: replace everywhere. *) type prog = string type arg = string type args = string list type command_line = (prog * arg list) type findlib_name = string type findlib_full = string type compiled_object = | Byte | Native | Best type dependency = | FindlibPackage of findlib_full * OASISVersion.comparator option | InternalLibrary of name type tool = | ExternalTool of name | InternalExecutable of name type vcs = | Darcs | Git | Svn | Cvs | Hg | Bzr | Arch | Monotone | OtherVCS of url type plugin_kind = [ `Configure | `Build | `Doc | `Test | `Install | `Extra ] type plugin_data_purpose = [ `Configure | `Build | `Install | `Clean | `Distclean | `Install | `Uninstall | `Test | `Doc | `Extra | `Other of string ] type 'a plugin = 'a * name * OASISVersion.t option type all_plugin = plugin_kind plugin type plugin_data = (all_plugin * plugin_data_purpose * (unit -> unit)) list type 'a conditional = 'a OASISExpr.choices type custom = { pre_command: (command_line option) conditional; post_command: (command_line option) conditional; } type common_section = { cs_name: name; cs_data: PropList.Data.t; cs_plugin_data: plugin_data; } type build_section = { bs_build: bool conditional; bs_install: bool conditional; bs_path: unix_dirname; bs_compiled_object: compiled_object; bs_build_depends: dependency list; bs_build_tools: tool list; bs_interface_patterns: OASISSourcePatterns.t list; bs_implementation_patterns: OASISSourcePatterns.t list; bs_c_sources: unix_filename list; bs_data_files: (unix_filename * unix_filename option) list; bs_findlib_extra_files: unix_filename list; bs_ccopt: args conditional; bs_cclib: args conditional; bs_dlllib: args conditional; bs_dllpath: args conditional; bs_byteopt: args conditional; bs_nativeopt: args conditional; } type library = { lib_modules: string list; lib_pack: bool; lib_internal_modules: string list; lib_findlib_parent: findlib_name option; lib_findlib_name: findlib_name option; lib_findlib_directory: unix_dirname option; lib_findlib_containers: findlib_name list; } type object_ = { obj_modules: string list; obj_findlib_fullname: findlib_name list option; obj_findlib_directory: unix_dirname option; } type executable = { exec_custom: bool; exec_main_is: unix_filename; } type flag = { flag_description: string option; flag_default: bool conditional; } type source_repository = { src_repo_type: vcs; src_repo_location: url; src_repo_browser: url option; src_repo_module: string option; src_repo_branch: string option; src_repo_tag: string option; src_repo_subdir: unix_filename option; } type test = { test_type: [`Test] plugin; test_command: command_line conditional; test_custom: custom; test_working_directory: unix_filename option; test_run: bool conditional; test_tools: tool list; } type doc_format = | HTML of unix_filename (* TODO: source filename. *) | DocText | PDF | PostScript | Info of unix_filename (* TODO: source filename. *) | DVI | OtherDoc type doc = { doc_type: [`Doc] plugin; doc_custom: custom; doc_build: bool conditional; doc_install: bool conditional; doc_install_dir: unix_filename; (* TODO: dest filename ?. *) doc_title: string; doc_authors: string list; doc_abstract: string option; doc_format: doc_format; (* TODO: src filename. *) doc_data_files: (unix_filename * unix_filename option) list; doc_build_tools: tool list; } type section = | Library of common_section * build_section * library | Object of common_section * build_section * object_ | Executable of common_section * build_section * executable | Flag of common_section * flag | SrcRepo of common_section * source_repository | Test of common_section * test | Doc of common_section * doc type section_kind = [ `Library | `Object | `Executable | `Flag | `SrcRepo | `Test | `Doc ] type package = { oasis_version: OASISVersion.t; ocaml_version: OASISVersion.comparator option; findlib_version: OASISVersion.comparator option; alpha_features: string list; beta_features: string list; name: package_name; version: OASISVersion.t; license: OASISLicense.t; license_file: unix_filename option; (* TODO: source filename. *) copyrights: string list; maintainers: string list; authors: string list; homepage: url option; bugreports: url option; synopsis: string; description: OASISText.t option; tags: string list; categories: url list; conf_type: [`Configure] plugin; conf_custom: custom; build_type: [`Build] plugin; build_custom: custom; install_type: [`Install] plugin; install_custom: custom; uninstall_custom: custom; clean_custom: custom; distclean_custom: custom; files_ab: unix_filename list; (* TODO: source filename. *) sections: section list; plugins: [`Extra] plugin list; disable_oasis_section: unix_filename list; (* TODO: source filename. *) schema_data: PropList.Data.t; plugin_data: plugin_data; } end module OASISFeatures = struct (* # 22 "src/oasis/OASISFeatures.ml" *) open OASISTypes open OASISUtils open OASISGettext open OASISVersion module MapPlugin = Map.Make (struct type t = plugin_kind * name let compare = Pervasives.compare end) module Data = struct type t = { oasis_version: OASISVersion.t; plugin_versions: OASISVersion.t option MapPlugin.t; alpha_features: string list; beta_features: string list; } let create oasis_version alpha_features beta_features = { oasis_version = oasis_version; plugin_versions = MapPlugin.empty; alpha_features = alpha_features; beta_features = beta_features } let of_package pkg = create pkg.OASISTypes.oasis_version pkg.OASISTypes.alpha_features pkg.OASISTypes.beta_features let add_plugin (plugin_kind, plugin_name, plugin_version) t = {t with plugin_versions = MapPlugin.add (plugin_kind, plugin_name) plugin_version t.plugin_versions} let plugin_version plugin_kind plugin_name t = MapPlugin.find (plugin_kind, plugin_name) t.plugin_versions let to_string t = Printf.sprintf "oasis_version: %s; alpha_features: %s; beta_features: %s; \ plugins_version: %s" (OASISVersion.string_of_version (t:t).oasis_version) (String.concat ", " t.alpha_features) (String.concat ", " t.beta_features) (String.concat ", " (MapPlugin.fold (fun (_, plg) ver_opt acc -> (plg^ (match ver_opt with | Some v -> " "^(OASISVersion.string_of_version v) | None -> "")) :: acc) t.plugin_versions [])) end type origin = | Field of string * string | Section of string | NoOrigin type stage = Alpha | Beta let string_of_stage = function | Alpha -> "alpha" | Beta -> "beta" let field_of_stage = function | Alpha -> "AlphaFeatures" | Beta -> "BetaFeatures" type publication = InDev of stage | SinceVersion of OASISVersion.t type t = { name: string; plugin: all_plugin option; publication: publication; description: unit -> string; } (* TODO: mutex protect this. *) let all_features = Hashtbl.create 13 let since_version ver_str = SinceVersion (version_of_string ver_str) let alpha = InDev Alpha let beta = InDev Beta let to_string t = Printf.sprintf "feature: %s; plugin: %s; publication: %s" (t:t).name (match t.plugin with | None -> "" | Some (_, nm, _) -> nm) (match t.publication with | InDev stage -> string_of_stage stage | SinceVersion ver -> ">= "^(OASISVersion.string_of_version ver)) let data_check t data origin = let no_message = "no message" in let check_feature features stage = let has_feature = List.mem (t:t).name features in if not has_feature then match (origin:origin) with | Field (fld, where) -> Some (Printf.sprintf (f_ "Field %s in %s is only available when feature %s \ is in field %s.") fld where t.name (field_of_stage stage)) | Section sct -> Some (Printf.sprintf (f_ "Section %s is only available when features %s \ is in field %s.") sct t.name (field_of_stage stage)) | NoOrigin -> Some no_message else None in let version_is_good ~min_version version fmt = let version_is_good = OASISVersion.comparator_apply version (OASISVersion.VGreaterEqual min_version) in Printf.ksprintf (fun str -> if version_is_good then None else Some str) fmt in match origin, t.plugin, t.publication with | _, _, InDev Alpha -> check_feature data.Data.alpha_features Alpha | _, _, InDev Beta -> check_feature data.Data.beta_features Beta | Field(fld, where), None, SinceVersion min_version -> version_is_good ~min_version data.Data.oasis_version (f_ "Field %s in %s is only valid since OASIS v%s, update \ OASISFormat field from '%s' to '%s' after checking \ OASIS changelog.") fld where (string_of_version min_version) (string_of_version data.Data.oasis_version) (string_of_version min_version) | Field(fld, where), Some(plugin_knd, plugin_name, _), SinceVersion min_version -> begin try let plugin_version_current = try match Data.plugin_version plugin_knd plugin_name data with | Some ver -> ver | None -> failwithf (f_ "Field %s in %s is only valid for the OASIS \ plugin %s since v%s, but no plugin version is \ defined in the _oasis file, change '%s' to \ '%s (%s)' in your _oasis file.") fld where plugin_name (string_of_version min_version) plugin_name plugin_name (string_of_version min_version) with Not_found -> failwithf (f_ "Field %s in %s is only valid when the OASIS plugin %s \ is defined.") fld where plugin_name in version_is_good ~min_version plugin_version_current (f_ "Field %s in %s is only valid for the OASIS plugin %s \ since v%s, update your plugin from '%s (%s)' to \ '%s (%s)' after checking the plugin's changelog.") fld where plugin_name (string_of_version min_version) plugin_name (string_of_version plugin_version_current) plugin_name (string_of_version min_version) with Failure msg -> Some msg end | Section sct, None, SinceVersion min_version -> version_is_good ~min_version data.Data.oasis_version (f_ "Section %s is only valid for since OASIS v%s, update \ OASISFormat field from '%s' to '%s' after checking OASIS \ changelog.") sct (string_of_version min_version) (string_of_version data.Data.oasis_version) (string_of_version min_version) | Section sct, Some(plugin_knd, plugin_name, _), SinceVersion min_version -> begin try let plugin_version_current = try match Data.plugin_version plugin_knd plugin_name data with | Some ver -> ver | None -> failwithf (f_ "Section %s is only valid for the OASIS \ plugin %s since v%s, but no plugin version is \ defined in the _oasis file, change '%s' to \ '%s (%s)' in your _oasis file.") sct plugin_name (string_of_version min_version) plugin_name plugin_name (string_of_version min_version) with Not_found -> failwithf (f_ "Section %s is only valid when the OASIS plugin %s \ is defined.") sct plugin_name in version_is_good ~min_version plugin_version_current (f_ "Section %s is only valid for the OASIS plugin %s \ since v%s, update your plugin from '%s (%s)' to \ '%s (%s)' after checking the plugin's changelog.") sct plugin_name (string_of_version min_version) plugin_name (string_of_version plugin_version_current) plugin_name (string_of_version min_version) with Failure msg -> Some msg end | NoOrigin, None, SinceVersion min_version -> version_is_good ~min_version data.Data.oasis_version "%s" no_message | NoOrigin, Some(plugin_knd, plugin_name, _), SinceVersion min_version -> begin try let plugin_version_current = match Data.plugin_version plugin_knd plugin_name data with | Some ver -> ver | None -> raise Not_found in version_is_good ~min_version plugin_version_current "%s" no_message with Not_found -> Some no_message end let data_assert t data origin = match data_check t data origin with | None -> () | Some str -> failwith str let data_test t data = match data_check t data NoOrigin with | None -> true | Some _ -> false let package_test t pkg = data_test t (Data.of_package pkg) let create ?plugin name publication description = let () = if Hashtbl.mem all_features name then failwithf "Feature '%s' is already declared." name in let t = { name = name; plugin = plugin; publication = publication; description = description; } in Hashtbl.add all_features name t; t let get_stage name = try (Hashtbl.find all_features name).publication with Not_found -> failwithf (f_ "Feature %s doesn't exist.") name let list () = Hashtbl.fold (fun _ v acc -> v :: acc) all_features [] (* * Real flags. *) let features = create "features_fields" (since_version "0.4") (fun () -> s_ "Enable to experiment not yet official features.") let flag_docs = create "flag_docs" (since_version "0.3") (fun () -> s_ "Make building docs require '-docs' flag at configure.") let flag_tests = create "flag_tests" (since_version "0.3") (fun () -> s_ "Make running tests require '-tests' flag at configure.") let pack = create "pack" (since_version "0.3") (fun () -> s_ "Allow to create packed library.") let section_object = create "section_object" beta (fun () -> s_ "Implement an object section.") let dynrun_for_release = create "dynrun_for_release" alpha (fun () -> s_ "Make '-setup-update dynamic' suitable for releasing project.") let compiled_setup_ml = create "compiled_setup_ml" alpha (fun () -> s_ "Compile the setup.ml and speed-up actions done with it.") let disable_oasis_section = create "disable_oasis_section" alpha (fun () -> s_ "Allow the OASIS section comments and digests to be omitted in \ generated files.") let no_automatic_syntax = create "no_automatic_syntax" alpha (fun () -> s_ "Disable the automatic inclusion of -syntax camlp4o for packages \ that matches the internal heuristic (if a dependency ends with \ a .syntax or is a well known syntax).") let findlib_directory = create "findlib_directory" beta (fun () -> s_ "Allow to install findlib libraries in sub-directories of the target \ findlib directory.") let findlib_extra_files = create "findlib_extra_files" beta (fun () -> s_ "Allow to install extra files for findlib libraries.") let source_patterns = create "source_patterns" alpha (fun () -> s_ "Customize mapping between module name and source file.") end module OASISSection = struct (* # 22 "src/oasis/OASISSection.ml" *) open OASISTypes let section_kind_common = function | Library (cs, _, _) -> `Library, cs | Object (cs, _, _) -> `Object, cs | Executable (cs, _, _) -> `Executable, cs | Flag (cs, _) -> `Flag, cs | SrcRepo (cs, _) -> `SrcRepo, cs | Test (cs, _) -> `Test, cs | Doc (cs, _) -> `Doc, cs let section_common sct = snd (section_kind_common sct) let section_common_set cs = function | Library (_, bs, lib) -> Library (cs, bs, lib) | Object (_, bs, obj) -> Object (cs, bs, obj) | Executable (_, bs, exec) -> Executable (cs, bs, exec) | Flag (_, flg) -> Flag (cs, flg) | SrcRepo (_, src_repo) -> SrcRepo (cs, src_repo) | Test (_, tst) -> Test (cs, tst) | Doc (_, doc) -> Doc (cs, doc) (** Key used to identify section *) let section_id sct = let k, cs = section_kind_common sct in k, cs.cs_name let string_of_section_kind = function | `Library -> "library" | `Object -> "object" | `Executable -> "executable" | `Flag -> "flag" | `SrcRepo -> "src repository" | `Test -> "test" | `Doc -> "doc" let string_of_section sct = let k, nm = section_id sct in (string_of_section_kind k)^" "^nm let section_find id scts = List.find (fun sct -> id = section_id sct) scts module CSection = struct type t = section let id = section_id let compare t1 t2 = compare (id t1) (id t2) let equal t1 t2 = (id t1) = (id t2) let hash t = Hashtbl.hash (id t) end module MapSection = Map.Make(CSection) module SetSection = Set.Make(CSection) end module OASISBuildSection = struct (* # 22 "src/oasis/OASISBuildSection.ml" *) open OASISTypes (* Look for a module file, considering capitalization or not. *) let find_module source_file_exists bs modul = let possible_lst = OASISSourcePatterns.all_possible_files (bs.bs_interface_patterns @ bs.bs_implementation_patterns) ~path:bs.bs_path ~modul in match List.filter source_file_exists possible_lst with | (fn :: _) as fn_lst -> `Sources (OASISUnixPath.chop_extension fn, fn_lst) | [] -> let open OASISUtils in let _, rev_lst = List.fold_left (fun (set, acc) fn -> let base_fn = OASISUnixPath.chop_extension fn in if SetString.mem base_fn set then set, acc else SetString.add base_fn set, base_fn :: acc) (SetString.empty, []) possible_lst in `No_sources (List.rev rev_lst) end module OASISExecutable = struct (* # 22 "src/oasis/OASISExecutable.ml" *) open OASISTypes let unix_exec_is (cs, bs, exec) is_native ext_dll suffix_program = let dir = OASISUnixPath.concat bs.bs_path (OASISUnixPath.dirname exec.exec_main_is) in let is_native_exec = match bs.bs_compiled_object with | Native -> true | Best -> is_native () | Byte -> false in OASISUnixPath.concat dir (cs.cs_name^(suffix_program ())), if not is_native_exec && not exec.exec_custom && bs.bs_c_sources <> [] then Some (dir^"/dll"^cs.cs_name^"_stubs"^(ext_dll ())) else None end module OASISLibrary = struct (* # 22 "src/oasis/OASISLibrary.ml" *) open OASISTypes open OASISGettext let find_module ~ctxt source_file_exists cs bs modul = match OASISBuildSection.find_module source_file_exists bs modul with | `Sources _ as res -> res | `No_sources _ as res -> OASISMessage.warning ~ctxt (f_ "Cannot find source file matching module '%s' in library %s.") modul cs.cs_name; OASISMessage.warning ~ctxt (f_ "Use InterfacePatterns or ImplementationPatterns to define \ this file with feature %S.") (OASISFeatures.source_patterns.OASISFeatures.name); res let source_unix_files ~ctxt (cs, bs, lib) source_file_exists = List.fold_left (fun acc modul -> match find_module ~ctxt source_file_exists cs bs modul with | `Sources (base_fn, lst) -> (base_fn, lst) :: acc | `No_sources _ -> acc) [] (lib.lib_modules @ lib.lib_internal_modules) let generated_unix_files ~ctxt ~is_native ~has_native_dynlink ~ext_lib ~ext_dll ~source_file_exists (cs, bs, lib) = let find_modules lst ext = let find_module modul = match find_module ~ctxt source_file_exists cs bs modul with | `Sources (_, [fn]) when ext <> "cmi" && Filename.check_suffix fn ".mli" -> None (* No implementation files for pure interface. *) | `Sources (base_fn, _) -> Some [base_fn] | `No_sources lst -> Some lst in List.fold_left (fun acc nm -> match find_module nm with | None -> acc | Some base_fns -> List.map (fun base_fn -> base_fn ^"."^ext) base_fns :: acc) [] lst in (* The .cmx that be compiled along *) let cmxs = let should_be_built = match bs.bs_compiled_object with | Native -> true | Best -> is_native | Byte -> false in if should_be_built then if lib.lib_pack then find_modules [cs.cs_name] "cmx" else find_modules (lib.lib_modules @ lib.lib_internal_modules) "cmx" else [] in let acc_nopath = [] in (* The headers and annot/cmt files that should be compiled along *) let headers = let sufx = if lib.lib_pack then [".cmti"; ".cmt"; ".annot"] else [".cmi"; ".cmti"; ".cmt"; ".annot"] in List.map (List.fold_left (fun accu s -> let dot = String.rindex s '.' in let base = String.sub s 0 dot in List.map ((^) base) sufx @ accu) []) (find_modules lib.lib_modules "cmi") in (* Compute what libraries should be built *) let acc_nopath = (* Add the packed header file if required *) let add_pack_header acc = if lib.lib_pack then [cs.cs_name^".cmi"; cs.cs_name^".cmti"; cs.cs_name^".cmt"] :: acc else acc in let byte acc = add_pack_header ([cs.cs_name^".cma"] :: acc) in let native acc = let acc = add_pack_header (if has_native_dynlink then [cs.cs_name^".cmxs"] :: acc else acc) in [cs.cs_name^".cmxa"] :: [cs.cs_name^ext_lib] :: acc in match bs.bs_compiled_object with | Native -> byte (native acc_nopath) | Best when is_native -> byte (native acc_nopath) | Byte | Best -> byte acc_nopath in (* Add C library to be built *) let acc_nopath = if bs.bs_c_sources <> [] then begin ["lib"^cs.cs_name^"_stubs"^ext_lib] :: if has_native_dynlink then ["dll"^cs.cs_name^"_stubs"^ext_dll] :: acc_nopath else acc_nopath end else begin acc_nopath end in (* All the files generated *) List.rev_append (List.rev_map (List.rev_map (OASISUnixPath.concat bs.bs_path)) acc_nopath) (headers @ cmxs) end module OASISObject = struct (* # 22 "src/oasis/OASISObject.ml" *) open OASISTypes open OASISGettext let find_module ~ctxt source_file_exists cs bs modul = match OASISBuildSection.find_module source_file_exists bs modul with | `Sources _ as res -> res | `No_sources _ as res -> OASISMessage.warning ~ctxt (f_ "Cannot find source file matching module '%s' in object %s.") modul cs.cs_name; OASISMessage.warning ~ctxt (f_ "Use InterfacePatterns or ImplementationPatterns to define \ this file with feature %S.") (OASISFeatures.source_patterns.OASISFeatures.name); res let source_unix_files ~ctxt (cs, bs, obj) source_file_exists = List.fold_left (fun acc modul -> match find_module ~ctxt source_file_exists cs bs modul with | `Sources (base_fn, lst) -> (base_fn, lst) :: acc | `No_sources _ -> acc) [] obj.obj_modules let generated_unix_files ~ctxt ~is_native ~source_file_exists (cs, bs, obj) = let find_module ext modul = match find_module ~ctxt source_file_exists cs bs modul with | `Sources (base_fn, _) -> [base_fn ^ ext] | `No_sources lst -> lst in let header, byte, native, c_object, f = match obj.obj_modules with | [ m ] -> (find_module ".cmi" m, find_module ".cmo" m, find_module ".cmx" m, find_module ".o" m, fun x -> x) | _ -> ([cs.cs_name ^ ".cmi"], [cs.cs_name ^ ".cmo"], [cs.cs_name ^ ".cmx"], [cs.cs_name ^ ".o"], OASISUnixPath.concat bs.bs_path) in List.map (List.map f) ( match bs.bs_compiled_object with | Native -> native :: c_object :: byte :: header :: [] | Best when is_native -> native :: c_object :: byte :: header :: [] | Byte | Best -> byte :: header :: []) end module OASISFindlib = struct (* # 22 "src/oasis/OASISFindlib.ml" *) open OASISTypes open OASISUtils open OASISGettext type library_name = name type findlib_part_name = name type 'a map_of_findlib_part_name = 'a OASISUtils.MapString.t exception InternalLibraryNotFound of library_name exception FindlibPackageNotFound of findlib_name type group_t = | Container of findlib_name * group_t list | Package of (findlib_name * common_section * build_section * [`Library of library | `Object of object_] * unix_dirname option * group_t list) type data = common_section * build_section * [`Library of library | `Object of object_] type tree = | Node of (data option) * (tree MapString.t) | Leaf of data let findlib_mapping pkg = (* Map from library name to either full findlib name or parts + parent. *) let fndlb_parts_of_lib_name = let fndlb_parts cs lib = let name = match lib.lib_findlib_name with | Some nm -> nm | None -> cs.cs_name in let name = String.concat "." (lib.lib_findlib_containers @ [name]) in name in List.fold_left (fun mp -> function | Library (cs, _, lib) -> begin let lib_name = cs.cs_name in let fndlb_parts = fndlb_parts cs lib in if MapString.mem lib_name mp then failwithf (f_ "The library name '%s' is used more than once.") lib_name; match lib.lib_findlib_parent with | Some lib_name_parent -> MapString.add lib_name (`Unsolved (lib_name_parent, fndlb_parts)) mp | None -> MapString.add lib_name (`Solved fndlb_parts) mp end | Object (cs, _, obj) -> begin let obj_name = cs.cs_name in if MapString.mem obj_name mp then failwithf (f_ "The object name '%s' is used more than once.") obj_name; let findlib_full_name = match obj.obj_findlib_fullname with | Some ns -> String.concat "." ns | None -> obj_name in MapString.add obj_name (`Solved findlib_full_name) mp end | Executable _ | Test _ | Flag _ | SrcRepo _ | Doc _ -> mp) MapString.empty pkg.sections in (* Solve the above graph to be only library name to full findlib name. *) let fndlb_name_of_lib_name = let rec solve visited mp lib_name lib_name_child = if SetString.mem lib_name visited then failwithf (f_ "Library '%s' is involved in a cycle \ with regard to findlib naming.") lib_name; let visited = SetString.add lib_name visited in try match MapString.find lib_name mp with | `Solved fndlb_nm -> fndlb_nm, mp | `Unsolved (lib_nm_parent, post_fndlb_nm) -> let pre_fndlb_nm, mp = solve visited mp lib_nm_parent lib_name in let fndlb_nm = pre_fndlb_nm^"."^post_fndlb_nm in fndlb_nm, MapString.add lib_name (`Solved fndlb_nm) mp with Not_found -> failwithf (f_ "Library '%s', which is defined as the findlib parent of \ library '%s', doesn't exist.") lib_name lib_name_child in let mp = MapString.fold (fun lib_name status mp -> match status with | `Solved _ -> (* Solved initialy, no need to go further *) mp | `Unsolved _ -> let _, mp = solve SetString.empty mp lib_name "" in mp) fndlb_parts_of_lib_name fndlb_parts_of_lib_name in MapString.map (function | `Solved fndlb_nm -> fndlb_nm | `Unsolved _ -> assert false) mp in (* Convert an internal library name to a findlib name. *) let findlib_name_of_library_name lib_nm = try MapString.find lib_nm fndlb_name_of_lib_name with Not_found -> raise (InternalLibraryNotFound lib_nm) in (* Add a library to the tree. *) let add sct mp = let fndlb_fullname = let cs, _, _ = sct in let lib_name = cs.cs_name in findlib_name_of_library_name lib_name in let rec add_children nm_lst (children: tree MapString.t) = match nm_lst with | (hd :: tl) -> begin let node = try add_node tl (MapString.find hd children) with Not_found -> (* New node *) new_node tl in MapString.add hd node children end | [] -> (* Should not have a nameless library. *) assert false and add_node tl node = if tl = [] then begin match node with | Node (None, children) -> Node (Some sct, children) | Leaf (cs', _, _) | Node (Some (cs', _, _), _) -> (* TODO: allow to merge Package, i.e. * archive(byte) = "foo.cma foo_init.cmo" *) let cs, _, _ = sct in failwithf (f_ "Library '%s' and '%s' have the same findlib name '%s'") cs.cs_name cs'.cs_name fndlb_fullname end else begin match node with | Leaf data -> Node (Some data, add_children tl MapString.empty) | Node (data_opt, children) -> Node (data_opt, add_children tl children) end and new_node = function | [] -> Leaf sct | hd :: tl -> Node (None, MapString.add hd (new_node tl) MapString.empty) in add_children (OASISString.nsplit fndlb_fullname '.') mp in let unix_directory dn lib = let directory = match lib with | `Library lib -> lib.lib_findlib_directory | `Object obj -> obj.obj_findlib_directory in match dn, directory with | None, None -> None | None, Some dn | Some dn, None -> Some dn | Some dn1, Some dn2 -> Some (OASISUnixPath.concat dn1 dn2) in let rec group_of_tree dn mp = MapString.fold (fun nm node acc -> let cur = match node with | Node (Some (cs, bs, lib), children) -> let current_dn = unix_directory dn lib in Package (nm, cs, bs, lib, current_dn, group_of_tree current_dn children) | Node (None, children) -> Container (nm, group_of_tree dn children) | Leaf (cs, bs, lib) -> let current_dn = unix_directory dn lib in Package (nm, cs, bs, lib, current_dn, []) in cur :: acc) mp [] in let group_mp = List.fold_left (fun mp -> function | Library (cs, bs, lib) -> add (cs, bs, `Library lib) mp | Object (cs, bs, obj) -> add (cs, bs, `Object obj) mp | _ -> mp) MapString.empty pkg.sections in let groups = group_of_tree None group_mp in let library_name_of_findlib_name = lazy begin (* Revert findlib_name_of_library_name. *) MapString.fold (fun k v mp -> MapString.add v k mp) fndlb_name_of_lib_name MapString.empty end in let library_name_of_findlib_name fndlb_nm = try MapString.find fndlb_nm (Lazy.force library_name_of_findlib_name) with Not_found -> raise (FindlibPackageNotFound fndlb_nm) in groups, findlib_name_of_library_name, library_name_of_findlib_name let findlib_of_group = function | Container (fndlb_nm, _) | Package (fndlb_nm, _, _, _, _, _) -> fndlb_nm let root_of_group grp = let rec root_lib_aux = (* We do a DFS in the group. *) function | Container (_, children) -> List.fold_left (fun res grp -> if res = None then root_lib_aux grp else res) None children | Package (_, cs, bs, lib, _, _) -> Some (cs, bs, lib) in match root_lib_aux grp with | Some res -> res | None -> failwithf (f_ "Unable to determine root library of findlib library '%s'") (findlib_of_group grp) end module OASISFlag = struct (* # 22 "src/oasis/OASISFlag.ml" *) end module OASISPackage = struct (* # 22 "src/oasis/OASISPackage.ml" *) end module OASISSourceRepository = struct (* # 22 "src/oasis/OASISSourceRepository.ml" *) end module OASISTest = struct (* # 22 "src/oasis/OASISTest.ml" *) end module OASISDocument = struct (* # 22 "src/oasis/OASISDocument.ml" *) end module OASISExec = struct (* # 22 "src/oasis/OASISExec.ml" *) open OASISGettext open OASISUtils open OASISMessage (* TODO: I don't like this quote, it is there because $(rm) foo expands to * 'rm -f' foo... *) let run ~ctxt ?f_exit_code ?(quote=true) cmd args = let cmd = if quote then if Sys.os_type = "Win32" then if String.contains cmd ' ' then (* Double the 1st double quote... win32... sigh *) "\""^(Filename.quote cmd) else cmd else Filename.quote cmd else cmd in let cmdline = String.concat " " (cmd :: args) in info ~ctxt (f_ "Running command '%s'") cmdline; match f_exit_code, Sys.command cmdline with | None, 0 -> () | None, i -> failwithf (f_ "Command '%s' terminated with error code %d") cmdline i | Some f, i -> f i let run_read_output ~ctxt ?f_exit_code cmd args = let fn = Filename.temp_file "oasis-" ".txt" in try begin let () = run ~ctxt ?f_exit_code cmd (args @ [">"; Filename.quote fn]) in let chn = open_in fn in let routput = ref [] in begin try while true do routput := (input_line chn) :: !routput done with End_of_file -> () end; close_in chn; Sys.remove fn; List.rev !routput end with e -> (try Sys.remove fn with _ -> ()); raise e let run_read_one_line ~ctxt ?f_exit_code cmd args = match run_read_output ~ctxt ?f_exit_code cmd args with | [fst] -> fst | lst -> failwithf (f_ "Command return unexpected output %S") (String.concat "\n" lst) end module OASISFileUtil = struct (* # 22 "src/oasis/OASISFileUtil.ml" *) open OASISGettext let file_exists_case fn = let dirname = Filename.dirname fn in let basename = Filename.basename fn in if Sys.file_exists dirname then if basename = Filename.current_dir_name then true else List.mem basename (Array.to_list (Sys.readdir dirname)) else false let find_file ?(case_sensitive=true) paths exts = (* Cardinal product of two list *) let ( * ) lst1 lst2 = List.flatten (List.map (fun a -> List.map (fun b -> a, b) lst2) lst1) in let rec combined_paths lst = match lst with | p1 :: p2 :: tl -> let acc = (List.map (fun (a, b) -> Filename.concat a b) (p1 * p2)) in combined_paths (acc :: tl) | [e] -> e | [] -> [] in let alternatives = List.map (fun (p, e) -> if String.length e > 0 && e.[0] <> '.' then p ^ "." ^ e else p ^ e) ((combined_paths paths) * exts) in List.find (fun file -> (if case_sensitive then file_exists_case file else Sys.file_exists file) && not (Sys.is_directory file) ) alternatives let which ~ctxt prg = let path_sep = match Sys.os_type with | "Win32" -> ';' | _ -> ':' in let path_lst = OASISString.nsplit (Sys.getenv "PATH") path_sep in let exec_ext = match Sys.os_type with | "Win32" -> "" :: (OASISString.nsplit (Sys.getenv "PATHEXT") path_sep) | _ -> [""] in find_file ~case_sensitive:false [path_lst; [prg]] exec_ext (**/**) let rec fix_dir dn = (* Windows hack because Sys.file_exists "src\\" = false when * Sys.file_exists "src" = true *) let ln = String.length dn in if Sys.os_type = "Win32" && ln > 0 && dn.[ln - 1] = '\\' then fix_dir (String.sub dn 0 (ln - 1)) else dn let q = Filename.quote (**/**) let cp ~ctxt ?(recurse=false) src tgt = if recurse then match Sys.os_type with | "Win32" -> OASISExec.run ~ctxt "xcopy" [q src; q tgt; "/E"] | _ -> OASISExec.run ~ctxt "cp" ["-r"; q src; q tgt] else OASISExec.run ~ctxt (match Sys.os_type with | "Win32" -> "copy" | _ -> "cp") [q src; q tgt] let mkdir ~ctxt tgt = OASISExec.run ~ctxt (match Sys.os_type with | "Win32" -> "md" | _ -> "mkdir") [q tgt] let rec mkdir_parent ~ctxt f tgt = let tgt = fix_dir tgt in if Sys.file_exists tgt then begin if not (Sys.is_directory tgt) then OASISUtils.failwithf (f_ "Cannot create directory '%s', a file of the same name already \ exists") tgt end else begin mkdir_parent ~ctxt f (Filename.dirname tgt); if not (Sys.file_exists tgt) then begin f tgt; mkdir ~ctxt tgt end end let rmdir ~ctxt tgt = if Sys.readdir tgt = [||] then begin match Sys.os_type with | "Win32" -> OASISExec.run ~ctxt "rd" [q tgt] | _ -> OASISExec.run ~ctxt "rm" ["-r"; q tgt] end else begin OASISMessage.error ~ctxt (f_ "Cannot remove directory '%s': not empty.") tgt end let glob ~ctxt fn = let basename = Filename.basename fn in if String.length basename >= 2 && basename.[0] = '*' && basename.[1] = '.' then begin let ext_len = (String.length basename) - 2 in let ext = String.sub basename 2 ext_len in let dirname = Filename.dirname fn in Array.fold_left (fun acc fn -> try let fn_ext = String.sub fn ((String.length fn) - ext_len) ext_len in if fn_ext = ext then (Filename.concat dirname fn) :: acc else acc with Invalid_argument _ -> acc) [] (Sys.readdir dirname) end else begin if file_exists_case fn then [fn] else [] end end # 3165 "setup.ml" module BaseEnvLight = struct (* # 22 "src/base/BaseEnvLight.ml" *) module MapString = Map.Make(String) type t = string MapString.t let default_filename = Filename.concat (Sys.getcwd ()) "setup.data" let load ?(allow_empty=false) ?(filename=default_filename) ?stream () = let line = ref 1 in let lexer st = let st_line = Stream.from (fun _ -> try match Stream.next st with | '\n' -> incr line; Some '\n' | c -> Some c with Stream.Failure -> None) in Genlex.make_lexer ["="] st_line in let rec read_file lxr mp = match Stream.npeek 3 lxr with | [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] -> Stream.junk lxr; Stream.junk lxr; Stream.junk lxr; read_file lxr (MapString.add nm value mp) | [] -> mp | _ -> failwith (Printf.sprintf "Malformed data file '%s' line %d" filename !line) in match stream with | Some st -> read_file (lexer st) MapString.empty | None -> if Sys.file_exists filename then begin let chn = open_in_bin filename in let st = Stream.of_channel chn in try let mp = read_file (lexer st) MapString.empty in close_in chn; mp with e -> close_in chn; raise e end else if allow_empty then begin MapString.empty end else begin failwith (Printf.sprintf "Unable to load environment, the file '%s' doesn't exist." filename) end let rec var_expand str env = let buff = Buffer.create ((String.length str) * 2) in Buffer.add_substitute buff (fun var -> try var_expand (MapString.find var env) env with Not_found -> failwith (Printf.sprintf "No variable %s defined when trying to expand %S." var str)) str; Buffer.contents buff let var_get name env = var_expand (MapString.find name env) env let var_choose lst env = OASISExpr.choose (fun nm -> var_get nm env) lst end # 3245 "setup.ml" module BaseContext = struct (* # 22 "src/base/BaseContext.ml" *) (* TODO: get rid of this module. *) open OASISContext let args () = fst (fspecs ()) let default = default end module BaseMessage = struct (* # 22 "src/base/BaseMessage.ml" *) (** Message to user, overrid for Base @author Sylvain Le Gall *) open OASISMessage open BaseContext let debug fmt = debug ~ctxt:!default fmt let info fmt = info ~ctxt:!default fmt let warning fmt = warning ~ctxt:!default fmt let error fmt = error ~ctxt:!default fmt end module BaseEnv = struct (* # 22 "src/base/BaseEnv.ml" *) open OASISGettext open OASISUtils open OASISContext open PropList module MapString = BaseEnvLight.MapString type origin_t = | ODefault | OGetEnv | OFileLoad | OCommandLine type cli_handle_t = | CLINone | CLIAuto | CLIWith | CLIEnable | CLIUser of (Arg.key * Arg.spec * Arg.doc) list type definition_t = { hide: bool; dump: bool; cli: cli_handle_t; arg_help: string option; group: string option; } let schema = Schema.create "environment" (* Environment data *) let env = Data.create () (* Environment data from file *) let env_from_file = ref MapString.empty (* Lexer for var *) let var_lxr = Genlex.make_lexer [] let rec var_expand str = let buff = Buffer.create ((String.length str) * 2) in Buffer.add_substitute buff (fun var -> try (* TODO: this is a quick hack to allow calling Test.Command * without defining executable name really. I.e. if there is * an exec Executable toto, then $(toto) should be replace * by its real name. It is however useful to have this function * for other variable that depend on the host and should be * written better than that. *) let st = var_lxr (Stream.of_string var) in match Stream.npeek 3 st with | [Genlex.Ident "utoh"; Genlex.Ident nm] -> OASISHostPath.of_unix (var_get nm) | [Genlex.Ident "utoh"; Genlex.String s] -> OASISHostPath.of_unix s | [Genlex.Ident "ocaml_escaped"; Genlex.Ident nm] -> String.escaped (var_get nm) | [Genlex.Ident "ocaml_escaped"; Genlex.String s] -> String.escaped s | [Genlex.Ident nm] -> var_get nm | _ -> failwithf (f_ "Unknown expression '%s' in variable expansion of %s.") var str with | Unknown_field (_, _) -> failwithf (f_ "No variable %s defined when trying to expand %S.") var str | Stream.Error e -> failwithf (f_ "Syntax error when parsing '%s' when trying to \ expand %S: %s") var str e) str; Buffer.contents buff and var_get name = let vl = try Schema.get schema env name with Unknown_field _ as e -> begin try MapString.find name !env_from_file with Not_found -> raise e end in var_expand vl let var_choose ?printer ?name lst = OASISExpr.choose ?printer ?name var_get lst let var_protect vl = let buff = Buffer.create (String.length vl) in String.iter (function | '$' -> Buffer.add_string buff "\\$" | c -> Buffer.add_char buff c) vl; Buffer.contents buff let var_define ?(hide=false) ?(dump=true) ?short_desc ?(cli=CLINone) ?arg_help ?group name (* TODO: type constraint on the fact that name must be a valid OCaml id *) dflt = let default = [ OFileLoad, (fun () -> MapString.find name !env_from_file); ODefault, dflt; OGetEnv, (fun () -> Sys.getenv name); ] in let extra = { hide = hide; dump = dump; cli = cli; arg_help = arg_help; group = group; } in (* Try to find a value that can be defined *) let var_get_low lst = let errors, res = List.fold_left (fun (errors, res) (_, v) -> if res = None then begin try errors, Some (v ()) with | Not_found -> errors, res | Failure rsn -> (rsn :: errors), res | e -> (Printexc.to_string e) :: errors, res end else errors, res) ([], None) (List.sort (fun (o1, _) (o2, _) -> Pervasives.compare o2 o1) lst) in match res, errors with | Some v, _ -> v | None, [] -> raise (Not_set (name, None)) | None, lst -> raise (Not_set (name, Some (String.concat (s_ ", ") lst))) in let help = match short_desc with | Some fs -> Some fs | None -> None in let var_get_lst = FieldRO.create ~schema ~name ~parse:(fun ?(context=ODefault) s -> [context, fun () -> s]) ~print:var_get_low ~default ~update:(fun ?context:_ x old_x -> x @ old_x) ?help extra in fun () -> var_expand (var_get_low (var_get_lst env)) let var_redefine ?hide ?dump ?short_desc ?cli ?arg_help ?group name dflt = if Schema.mem schema name then begin (* TODO: look suspsicious, we want to memorize dflt not dflt () *) Schema.set schema env ~context:ODefault name (dflt ()); fun () -> var_get name end else begin var_define ?hide ?dump ?short_desc ?cli ?arg_help ?group name dflt end let var_ignore (_: unit -> string) = () let print_hidden = var_define ~hide:true ~dump:false ~cli:CLIAuto ~arg_help:"Print even non-printable variable. (debug)" "print_hidden" (fun () -> "false") let var_all () = List.rev (Schema.fold (fun acc nm def _ -> if not def.hide || bool_of_string (print_hidden ()) then nm :: acc else acc) [] schema) let default_filename = in_srcdir "setup.data" let load ~ctxt ?(allow_empty=false) ?(filename=default_filename) () = let open OASISFileSystem in env_from_file := let repr_filename = ctxt.srcfs#string_of_filename filename in if ctxt.srcfs#file_exists filename then begin let buf = Buffer.create 13 in defer_close (ctxt.srcfs#open_in ~mode:binary_in filename) (read_all buf); defer_close (ctxt.srcfs#open_in ~mode:binary_in filename) (fun rdr -> OASISMessage.info ~ctxt "Loading environment from %S." repr_filename; BaseEnvLight.load ~allow_empty ~filename:(repr_filename) ~stream:(stream_of_reader rdr) ()) end else if allow_empty then begin BaseEnvLight.MapString.empty end else begin failwith (Printf.sprintf (f_ "Unable to load environment, the file '%s' doesn't exist.") repr_filename) end let unload () = env_from_file := MapString.empty; Data.clear env let dump ~ctxt ?(filename=default_filename) () = let open OASISFileSystem in defer_close (ctxt.OASISContext.srcfs#open_out ~mode:binary_out filename) (fun wrtr -> let buf = Buffer.create 63 in let output nm value = Buffer.add_string buf (Printf.sprintf "%s=%S\n" nm value) in let mp_todo = (* Dump data from schema *) Schema.fold (fun mp_todo nm def _ -> if def.dump then begin try output nm (Schema.get schema env nm) with Not_set _ -> () end; MapString.remove nm mp_todo) !env_from_file schema in (* Dump data defined outside of schema *) MapString.iter output mp_todo; wrtr#output buf) let print () = let printable_vars = Schema.fold (fun acc nm def short_descr_opt -> if not def.hide || bool_of_string (print_hidden ()) then begin try let value = Schema.get schema env nm in let txt = match short_descr_opt with | Some s -> s () | None -> nm in (txt, value) :: acc with Not_set _ -> acc end else acc) [] schema in let max_length = List.fold_left max 0 (List.rev_map String.length (List.rev_map fst printable_vars)) in let dot_pad str = String.make ((max_length - (String.length str)) + 3) '.' in Printf.printf "\nConfiguration:\n"; List.iter (fun (name, value) -> Printf.printf "%s: %s" name (dot_pad name); if value = "" then Printf.printf "\n" else Printf.printf " %s\n" value) (List.rev printable_vars); Printf.printf "\n%!" let args () = let arg_concat = OASISUtils.varname_concat ~hyphen:'-' in [ "--override", Arg.Tuple ( let rvr = ref "" in let rvl = ref "" in [ Arg.Set_string rvr; Arg.Set_string rvl; Arg.Unit (fun () -> Schema.set schema env ~context:OCommandLine !rvr !rvl) ] ), "var+val Override any configuration variable."; ] @ List.flatten (Schema.fold (fun acc name def short_descr_opt -> let var_set s = Schema.set schema env ~context:OCommandLine name s in let arg_name = OASISUtils.varname_of_string ~hyphen:'-' name in let hlp = match short_descr_opt with | Some txt -> txt () | None -> "" in let arg_hlp = match def.arg_help with | Some s -> s | None -> "str" in let default_value = try Printf.sprintf (f_ " [%s]") (Schema.get schema env name) with Not_set _ -> "" in let args = match def.cli with | CLINone -> [] | CLIAuto -> [ arg_concat "--" arg_name, Arg.String var_set, Printf.sprintf (f_ "%s %s%s") arg_hlp hlp default_value ] | CLIWith -> [ arg_concat "--with-" arg_name, Arg.String var_set, Printf.sprintf (f_ "%s %s%s") arg_hlp hlp default_value ] | CLIEnable -> let dflt = if default_value = " [true]" then s_ " [default: enabled]" else s_ " [default: disabled]" in [ arg_concat "--enable-" arg_name, Arg.Unit (fun () -> var_set "true"), Printf.sprintf (f_ " %s%s") hlp dflt; arg_concat "--disable-" arg_name, Arg.Unit (fun () -> var_set "false"), Printf.sprintf (f_ " %s%s") hlp dflt ] | CLIUser lst -> lst in args :: acc) [] schema) end module BaseArgExt = struct (* # 22 "src/base/BaseArgExt.ml" *) open OASISUtils open OASISGettext let parse argv args = (* Simulate command line for Arg *) let current = ref 0 in try Arg.parse_argv ~current:current (Array.concat [[|"none"|]; argv]) (Arg.align args) (failwithf (f_ "Don't know what to do with arguments: '%s'")) (s_ "configure options:") with | Arg.Help txt -> print_endline txt; exit 0 | Arg.Bad txt -> prerr_endline txt; exit 1 end module BaseCheck = struct (* # 22 "src/base/BaseCheck.ml" *) open BaseEnv open BaseMessage open OASISUtils open OASISGettext let prog_best prg prg_lst = var_redefine prg (fun () -> let alternate = List.fold_left (fun res e -> match res with | Some _ -> res | None -> try Some (OASISFileUtil.which ~ctxt:!BaseContext.default e) with Not_found -> None) None prg_lst in match alternate with | Some prg -> prg | None -> raise Not_found) let prog prg = prog_best prg [prg] let prog_opt prg = prog_best prg [prg^".opt"; prg] let ocamlfind = prog "ocamlfind" let version var_prefix cmp fversion () = (* Really compare version provided *) let var = var_prefix^"_version_"^(OASISVersion.varname_of_comparator cmp) in var_redefine ~hide:true var (fun () -> let version_str = match fversion () with | "[Distributed with OCaml]" -> begin try (var_get "ocaml_version") with Not_found -> warning (f_ "Variable ocaml_version not defined, fallback \ to default"); Sys.ocaml_version end | res -> res in let version = OASISVersion.version_of_string version_str in if OASISVersion.comparator_apply version cmp then version_str else failwithf (f_ "Cannot satisfy version constraint on %s: %s (version: %s)") var_prefix (OASISVersion.string_of_comparator cmp) version_str) () let package_version pkg = OASISExec.run_read_one_line ~ctxt:!BaseContext.default (ocamlfind ()) ["query"; "-format"; "%v"; pkg] let package ?version_comparator pkg () = let var = OASISUtils.varname_concat "pkg_" (OASISUtils.varname_of_string pkg) in let findlib_dir pkg = let dir = OASISExec.run_read_one_line ~ctxt:!BaseContext.default (ocamlfind ()) ["query"; "-format"; "%d"; pkg] in if Sys.file_exists dir && Sys.is_directory dir then dir else failwithf (f_ "When looking for findlib package %s, \ directory %s return doesn't exist") pkg dir in let vl = var_redefine var (fun () -> findlib_dir pkg) () in ( match version_comparator with | Some ver_cmp -> ignore (version var ver_cmp (fun _ -> package_version pkg) ()) | None -> () ); vl end module BaseOCamlcConfig = struct (* # 22 "src/base/BaseOCamlcConfig.ml" *) open BaseEnv open OASISUtils open OASISGettext module SMap = Map.Make(String) let ocamlc = BaseCheck.prog_opt "ocamlc" let ocamlc_config_map = (* Map name to value for ocamlc -config output (name ^": "^value) *) let rec split_field mp lst = match lst with | line :: tl -> let mp = try let pos_semicolon = String.index line ':' in if pos_semicolon > 1 then ( let name = String.sub line 0 pos_semicolon in let linelen = String.length line in let value = if linelen > pos_semicolon + 2 then String.sub line (pos_semicolon + 2) (linelen - pos_semicolon - 2) else "" in SMap.add name value mp ) else ( mp ) with Not_found -> ( mp ) in split_field mp tl | [] -> mp in let cache = lazy (var_protect (Marshal.to_string (split_field SMap.empty (OASISExec.run_read_output ~ctxt:!BaseContext.default (ocamlc ()) ["-config"])) [])) in var_redefine "ocamlc_config_map" ~hide:true ~dump:false (fun () -> (* TODO: update if ocamlc change !!! *) Lazy.force cache) let var_define nm = (* Extract data from ocamlc -config *) let avlbl_config_get () = Marshal.from_string (ocamlc_config_map ()) 0 in let chop_version_suffix s = try String.sub s 0 (String.index s '+') with _ -> s in let nm_config, value_config = match nm with | "ocaml_version" -> "version", chop_version_suffix | _ -> nm, (fun x -> x) in var_redefine nm (fun () -> try let map = avlbl_config_get () in let value = SMap.find nm_config map in value_config value with Not_found -> failwithf (f_ "Cannot find field '%s' in '%s -config' output") nm (ocamlc ())) end module BaseStandardVar = struct (* # 22 "src/base/BaseStandardVar.ml" *) open OASISGettext open OASISTypes open BaseCheck open BaseEnv let ocamlfind = BaseCheck.ocamlfind let ocamlc = BaseOCamlcConfig.ocamlc let ocamlopt = prog_opt "ocamlopt" let ocamlbuild = prog "ocamlbuild" (**/**) let rpkg = ref None let pkg_get () = match !rpkg with | Some pkg -> pkg | None -> failwith (s_ "OASIS Package is not set") let var_cond = ref [] let var_define_cond ~since_version f dflt = let holder = ref (fun () -> dflt) in let since_version = OASISVersion.VGreaterEqual (OASISVersion.version_of_string since_version) in var_cond := (fun ver -> if OASISVersion.comparator_apply ver since_version then holder := f ()) :: !var_cond; fun () -> !holder () (**/**) let pkg_name = var_define ~short_desc:(fun () -> s_ "Package name") "pkg_name" (fun () -> (pkg_get ()).name) let pkg_version = var_define ~short_desc:(fun () -> s_ "Package version") "pkg_version" (fun () -> (OASISVersion.string_of_version (pkg_get ()).version)) let c = BaseOCamlcConfig.var_define let os_type = c "os_type" let system = c "system" let architecture = c "architecture" let ccomp_type = c "ccomp_type" let ocaml_version = c "ocaml_version" (* TODO: Check standard variable presence at runtime *) let standard_library_default = c "standard_library_default" let standard_library = c "standard_library" let standard_runtime = c "standard_runtime" let bytecomp_c_compiler = c "bytecomp_c_compiler" let native_c_compiler = c "native_c_compiler" let model = c "model" let ext_obj = c "ext_obj" let ext_asm = c "ext_asm" let ext_lib = c "ext_lib" let ext_dll = c "ext_dll" let default_executable_name = c "default_executable_name" let systhread_supported = c "systhread_supported" let flexlink = BaseCheck.prog "flexlink" let flexdll_version = var_define ~short_desc:(fun () -> "FlexDLL version (Win32)") "flexdll_version" (fun () -> let lst = OASISExec.run_read_output ~ctxt:!BaseContext.default (flexlink ()) ["-help"] in match lst with | line :: _ -> Scanf.sscanf line "FlexDLL version %s" (fun ver -> ver) | [] -> raise Not_found) (**/**) let p name hlp dflt = var_define ~short_desc:hlp ~cli:CLIAuto ~arg_help:"dir" name dflt let (/) a b = if os_type () = Sys.os_type then Filename.concat a b else if os_type () = "Unix" || os_type () = "Cygwin" then OASISUnixPath.concat a b else OASISUtils.failwithf (f_ "Cannot handle os_type %s filename concat") (os_type ()) (**/**) let prefix = p "prefix" (fun () -> s_ "Install architecture-independent files dir") (fun () -> match os_type () with | "Win32" -> let program_files = Sys.getenv "PROGRAMFILES" in program_files/(pkg_name ()) | _ -> "/usr/local") let exec_prefix = p "exec_prefix" (fun () -> s_ "Install architecture-dependent files in dir") (fun () -> "$prefix") let bindir = p "bindir" (fun () -> s_ "User executables") (fun () -> "$exec_prefix"/"bin") let sbindir = p "sbindir" (fun () -> s_ "System admin executables") (fun () -> "$exec_prefix"/"sbin") let libexecdir = p "libexecdir" (fun () -> s_ "Program executables") (fun () -> "$exec_prefix"/"libexec") let sysconfdir = p "sysconfdir" (fun () -> s_ "Read-only single-machine data") (fun () -> "$prefix"/"etc") let sharedstatedir = p "sharedstatedir" (fun () -> s_ "Modifiable architecture-independent data") (fun () -> "$prefix"/"com") let localstatedir = p "localstatedir" (fun () -> s_ "Modifiable single-machine data") (fun () -> "$prefix"/"var") let libdir = p "libdir" (fun () -> s_ "Object code libraries") (fun () -> "$exec_prefix"/"lib") let datarootdir = p "datarootdir" (fun () -> s_ "Read-only arch-independent data root") (fun () -> "$prefix"/"share") let datadir = p "datadir" (fun () -> s_ "Read-only architecture-independent data") (fun () -> "$datarootdir") let infodir = p "infodir" (fun () -> s_ "Info documentation") (fun () -> "$datarootdir"/"info") let localedir = p "localedir" (fun () -> s_ "Locale-dependent data") (fun () -> "$datarootdir"/"locale") let mandir = p "mandir" (fun () -> s_ "Man documentation") (fun () -> "$datarootdir"/"man") let docdir = p "docdir" (fun () -> s_ "Documentation root") (fun () -> "$datarootdir"/"doc"/"$pkg_name") let htmldir = p "htmldir" (fun () -> s_ "HTML documentation") (fun () -> "$docdir") let dvidir = p "dvidir" (fun () -> s_ "DVI documentation") (fun () -> "$docdir") let pdfdir = p "pdfdir" (fun () -> s_ "PDF documentation") (fun () -> "$docdir") let psdir = p "psdir" (fun () -> s_ "PS documentation") (fun () -> "$docdir") let destdir = p "destdir" (fun () -> s_ "Prepend a path when installing package") (fun () -> raise (PropList.Not_set ("destdir", Some (s_ "undefined by construct")))) let findlib_version = var_define "findlib_version" (fun () -> BaseCheck.package_version "findlib") let is_native = var_define "is_native" (fun () -> try let _s: string = ocamlopt () in "true" with PropList.Not_set _ -> let _s: string = ocamlc () in "false") let ext_program = var_define "suffix_program" (fun () -> match os_type () with | "Win32" | "Cygwin" -> ".exe" | _ -> "") let rm = var_define ~short_desc:(fun () -> s_ "Remove a file.") "rm" (fun () -> match os_type () with | "Win32" -> "del" | _ -> "rm -f") let rmdir = var_define ~short_desc:(fun () -> s_ "Remove a directory.") "rmdir" (fun () -> match os_type () with | "Win32" -> "rd" | _ -> "rm -rf") let debug = var_define ~short_desc:(fun () -> s_ "Turn ocaml debug flag on") ~cli:CLIEnable "debug" (fun () -> "true") let profile = var_define ~short_desc:(fun () -> s_ "Turn ocaml profile flag on") ~cli:CLIEnable "profile" (fun () -> "false") let tests = var_define_cond ~since_version:"0.3" (fun () -> var_define ~short_desc:(fun () -> s_ "Compile tests executable and library and run them") ~cli:CLIEnable "tests" (fun () -> "false")) "true" let docs = var_define_cond ~since_version:"0.3" (fun () -> var_define ~short_desc:(fun () -> s_ "Create documentations") ~cli:CLIEnable "docs" (fun () -> "true")) "true" let native_dynlink = var_define ~short_desc:(fun () -> s_ "Compiler support generation of .cmxs.") ~cli:CLINone "native_dynlink" (fun () -> let res = let ocaml_lt_312 () = OASISVersion.comparator_apply (OASISVersion.version_of_string (ocaml_version ())) (OASISVersion.VLesser (OASISVersion.version_of_string "3.12.0")) in let flexdll_lt_030 () = OASISVersion.comparator_apply (OASISVersion.version_of_string (flexdll_version ())) (OASISVersion.VLesser (OASISVersion.version_of_string "0.30")) in let has_native_dynlink = let ocamlfind = ocamlfind () in try let fn = OASISExec.run_read_one_line ~ctxt:!BaseContext.default ocamlfind ["query"; "-predicates"; "native"; "dynlink"; "-format"; "%d/%a"] in Sys.file_exists fn with _ -> false in if not has_native_dynlink then false else if ocaml_lt_312 () then false else if (os_type () = "Win32" || os_type () = "Cygwin") && flexdll_lt_030 () then begin BaseMessage.warning (f_ ".cmxs generation disabled because FlexDLL needs to be \ at least 0.30. Please upgrade FlexDLL from %s to 0.30.") (flexdll_version ()); false end else true in string_of_bool res) let init pkg = rpkg := Some pkg; List.iter (fun f -> f pkg.oasis_version) !var_cond end module BaseFileAB = struct (* # 22 "src/base/BaseFileAB.ml" *) open BaseEnv open OASISGettext open BaseMessage open OASISContext let to_filename fn = if not (Filename.check_suffix fn ".ab") then warning (f_ "File '%s' doesn't have '.ab' extension") fn; OASISFileSystem.of_unix_filename (Filename.chop_extension fn) let replace ~ctxt fn_lst = let open OASISFileSystem in let ibuf, obuf = Buffer.create 13, Buffer.create 13 in List.iter (fun fn -> Buffer.clear ibuf; Buffer.clear obuf; defer_close (ctxt.srcfs#open_in (of_unix_filename fn)) (read_all ibuf); Buffer.add_string obuf (var_expand (Buffer.contents ibuf)); defer_close (ctxt.srcfs#open_out (to_filename fn)) (fun wrtr -> wrtr#output obuf)) fn_lst end module BaseLog = struct (* # 22 "src/base/BaseLog.ml" *) open OASISUtils open OASISContext open OASISGettext open OASISFileSystem let default_filename = in_srcdir "setup.log" let load ~ctxt () = let module SetTupleString = Set.Make (struct type t = string * string let compare (s11, s12) (s21, s22) = match String.compare s11 s21 with | 0 -> String.compare s12 s22 | n -> n end) in if ctxt.srcfs#file_exists default_filename then begin defer_close (ctxt.srcfs#open_in default_filename) (fun rdr -> let line = ref 1 in let lxr = Genlex.make_lexer [] (stream_of_reader rdr) in let rec read_aux (st, lst) = match Stream.npeek 2 lxr with | [Genlex.String e; Genlex.String d] -> let t = e, d in Stream.junk lxr; Stream.junk lxr; if SetTupleString.mem t st then read_aux (st, lst) else read_aux (SetTupleString.add t st, t :: lst) | [] -> List.rev lst | _ -> failwithf (f_ "Malformed log file '%s' at line %d") (ctxt.srcfs#string_of_filename default_filename) !line in read_aux (SetTupleString.empty, [])) end else begin [] end let register ~ctxt event data = defer_close (ctxt.srcfs#open_out ~mode:[Open_append; Open_creat; Open_text] ~perm:0o644 default_filename) (fun wrtr -> let buf = Buffer.create 13 in Printf.bprintf buf "%S %S\n" event data; wrtr#output buf) let unregister ~ctxt event data = let lst = load ~ctxt () in let buf = Buffer.create 13 in List.iter (fun (e, d) -> if e <> event || d <> data then Printf.bprintf buf "%S %S\n" e d) lst; if Buffer.length buf > 0 then defer_close (ctxt.srcfs#open_out default_filename) (fun wrtr -> wrtr#output buf) else ctxt.srcfs#remove default_filename let filter ~ctxt events = let st_events = SetString.of_list events in List.filter (fun (e, _) -> SetString.mem e st_events) (load ~ctxt ()) let exists ~ctxt event data = List.exists (fun v -> (event, data) = v) (load ~ctxt ()) end module BaseBuilt = struct (* # 22 "src/base/BaseBuilt.ml" *) open OASISTypes open OASISGettext open BaseStandardVar open BaseMessage type t = | BExec (* Executable *) | BExecLib (* Library coming with executable *) | BLib (* Library *) | BObj (* Library *) | BDoc (* Document *) let to_log_event_file t nm = "built_"^ (match t with | BExec -> "exec" | BExecLib -> "exec_lib" | BLib -> "lib" | BObj -> "obj" | BDoc -> "doc")^ "_"^nm let to_log_event_done t nm = "is_"^(to_log_event_file t nm) let register ~ctxt t nm lst = BaseLog.register ~ctxt (to_log_event_done t nm) "true"; List.iter (fun alt -> let registered = List.fold_left (fun registered fn -> if OASISFileUtil.file_exists_case fn then begin BaseLog.register ~ctxt (to_log_event_file t nm) (if Filename.is_relative fn then Filename.concat (Sys.getcwd ()) fn else fn); true end else begin registered end) false alt in if not registered then warning (f_ "Cannot find an existing alternative files among: %s") (String.concat (s_ ", ") alt)) lst let unregister ~ctxt t nm = List.iter (fun (e, d) -> BaseLog.unregister ~ctxt e d) (BaseLog.filter ~ctxt [to_log_event_file t nm; to_log_event_done t nm]) let fold ~ctxt t nm f acc = List.fold_left (fun acc (_, fn) -> if OASISFileUtil.file_exists_case fn then begin f acc fn end else begin warning (f_ "File '%s' has been marked as built \ for %s but doesn't exist") fn (Printf.sprintf (match t with | BExec | BExecLib -> (f_ "executable %s") | BLib -> (f_ "library %s") | BObj -> (f_ "object %s") | BDoc -> (f_ "documentation %s")) nm); acc end) acc (BaseLog.filter ~ctxt [to_log_event_file t nm]) let is_built ~ctxt t nm = List.fold_left (fun _ (_, d) -> try bool_of_string d with _ -> false) false (BaseLog.filter ~ctxt [to_log_event_done t nm]) let of_executable ffn (cs, bs, exec) = let unix_exec_is, unix_dll_opt = OASISExecutable.unix_exec_is (cs, bs, exec) (fun () -> bool_of_string (is_native ())) ext_dll ext_program in let evs = (BExec, cs.cs_name, [[ffn unix_exec_is]]) :: (match unix_dll_opt with | Some fn -> [BExecLib, cs.cs_name, [[ffn fn]]] | None -> []) in evs, unix_exec_is, unix_dll_opt let of_library ffn (cs, bs, lib) = let unix_lst = OASISLibrary.generated_unix_files ~ctxt:!BaseContext.default ~source_file_exists:(fun fn -> OASISFileUtil.file_exists_case (OASISHostPath.of_unix fn)) ~is_native:(bool_of_string (is_native ())) ~has_native_dynlink:(bool_of_string (native_dynlink ())) ~ext_lib:(ext_lib ()) ~ext_dll:(ext_dll ()) (cs, bs, lib) in let evs = [BLib, cs.cs_name, List.map (List.map ffn) unix_lst] in evs, unix_lst let of_object ffn (cs, bs, obj) = let unix_lst = OASISObject.generated_unix_files ~ctxt:!BaseContext.default ~source_file_exists:(fun fn -> OASISFileUtil.file_exists_case (OASISHostPath.of_unix fn)) ~is_native:(bool_of_string (is_native ())) (cs, bs, obj) in let evs = [BObj, cs.cs_name, List.map (List.map ffn) unix_lst] in evs, unix_lst end module BaseCustom = struct (* # 22 "src/base/BaseCustom.ml" *) open BaseEnv open BaseMessage open OASISTypes open OASISGettext let run cmd args extra_args = OASISExec.run ~ctxt:!BaseContext.default ~quote:false (var_expand cmd) (List.map var_expand (args @ (Array.to_list extra_args))) let hook ?(failsafe=false) cstm f e = let optional_command lst = let printer = function | Some (cmd, args) -> String.concat " " (cmd :: args) | None -> s_ "No command" in match var_choose ~name:(s_ "Pre/Post Command") ~printer lst with | Some (cmd, args) -> begin try run cmd args [||] with e when failsafe -> warning (f_ "Command '%s' fail with error: %s") (String.concat " " (cmd :: args)) (match e with | Failure msg -> msg | e -> Printexc.to_string e) end | None -> () in let res = optional_command cstm.pre_command; f e in optional_command cstm.post_command; res end module BaseDynVar = struct (* # 22 "src/base/BaseDynVar.ml" *) open OASISTypes open OASISGettext open BaseEnv open BaseBuilt let init ~ctxt pkg = (* TODO: disambiguate exec vs other variable by adding exec_VARNAME. *) (* TODO: provide compile option for library libary_byte_args_VARNAME... *) List.iter (function | Executable (cs, bs, _) -> if var_choose bs.bs_build then var_ignore (var_redefine (* We don't save this variable *) ~dump:false ~short_desc:(fun () -> Printf.sprintf (f_ "Filename of executable '%s'") cs.cs_name) (OASISUtils.varname_of_string cs.cs_name) (fun () -> let fn_opt = fold ~ctxt BExec cs.cs_name (fun _ fn -> Some fn) None in match fn_opt with | Some fn -> fn | None -> raise (PropList.Not_set (cs.cs_name, Some (Printf.sprintf (f_ "Executable '%s' not yet built.") cs.cs_name))))) | Library _ | Object _ | Flag _ | Test _ | SrcRepo _ | Doc _ -> ()) pkg.sections end module BaseTest = struct (* # 22 "src/base/BaseTest.ml" *) open BaseEnv open BaseMessage open OASISTypes open OASISGettext let test ~ctxt lst pkg extra_args = let one_test (failure, n) (test_plugin, cs, test) = if var_choose ~name:(Printf.sprintf (f_ "test %s run") cs.cs_name) ~printer:string_of_bool test.test_run then begin let () = info (f_ "Running test '%s'") cs.cs_name in let back_cwd = match test.test_working_directory with | Some dir -> let cwd = Sys.getcwd () in let chdir d = info (f_ "Changing directory to '%s'") d; Sys.chdir d in chdir dir; fun () -> chdir cwd | None -> fun () -> () in try let failure_percent = BaseCustom.hook test.test_custom (test_plugin ~ctxt pkg (cs, test)) extra_args in back_cwd (); (failure_percent +. failure, n + 1) with e -> begin back_cwd (); raise e end end else begin info (f_ "Skipping test '%s'") cs.cs_name; (failure, n) end in let failed, n = List.fold_left one_test (0.0, 0) lst in let failure_percent = if n = 0 then 0.0 else failed /. (float_of_int n) in let msg = Printf.sprintf (f_ "Tests had a %.2f%% failure rate") (100. *. failure_percent) in if failure_percent > 0.0 then failwith msg else info "%s" msg; (* Possible explanation why the tests where not run. *) if OASISFeatures.package_test OASISFeatures.flag_tests pkg && not (bool_of_string (BaseStandardVar.tests ())) && lst <> [] then BaseMessage.warning "Tests are turned off, consider enabling with \ 'ocaml setup.ml -configure --enable-tests'" end module BaseDoc = struct (* # 22 "src/base/BaseDoc.ml" *) open BaseEnv open BaseMessage open OASISTypes open OASISGettext let doc ~ctxt lst pkg extra_args = let one_doc (doc_plugin, cs, doc) = if var_choose ~name:(Printf.sprintf (f_ "documentation %s build") cs.cs_name) ~printer:string_of_bool doc.doc_build then begin info (f_ "Building documentation '%s'") cs.cs_name; BaseCustom.hook doc.doc_custom (doc_plugin ~ctxt pkg (cs, doc)) extra_args end in List.iter one_doc lst; if OASISFeatures.package_test OASISFeatures.flag_docs pkg && not (bool_of_string (BaseStandardVar.docs ())) && lst <> [] then BaseMessage.warning "Docs are turned off, consider enabling with \ 'ocaml setup.ml -configure --enable-docs'" end module BaseSetup = struct (* # 22 "src/base/BaseSetup.ml" *) open OASISContext open BaseEnv open BaseMessage open OASISTypes open OASISGettext open OASISUtils type std_args_fun = ctxt:OASISContext.t -> package -> string array -> unit type ('a, 'b) section_args_fun = name * (ctxt:OASISContext.t -> package -> (common_section * 'a) -> string array -> 'b) type t = { configure: std_args_fun; build: std_args_fun; doc: ((doc, unit) section_args_fun) list; test: ((test, float) section_args_fun) list; install: std_args_fun; uninstall: std_args_fun; clean: std_args_fun list; clean_doc: (doc, unit) section_args_fun list; clean_test: (test, unit) section_args_fun list; distclean: std_args_fun list; distclean_doc: (doc, unit) section_args_fun list; distclean_test: (test, unit) section_args_fun list; package: package; oasis_fn: string option; oasis_version: string; oasis_digest: Digest.t option; oasis_exec: string option; oasis_setup_args: string list; setup_update: bool; } (* Associate a plugin function with data from package *) let join_plugin_sections filter_map lst = List.rev (List.fold_left (fun acc sct -> match filter_map sct with | Some e -> e :: acc | None -> acc) [] lst) (* Search for plugin data associated with a section name *) let lookup_plugin_section plugin action nm lst = try List.assoc nm lst with Not_found -> failwithf (f_ "Cannot find plugin %s matching section %s for %s action") plugin nm action let configure ~ctxt t args = (* Run configure *) BaseCustom.hook t.package.conf_custom (fun () -> (* Reload if preconf has changed it *) begin try unload (); load ~ctxt (); with _ -> () end; (* Run plugin's configure *) t.configure ~ctxt t.package args; (* Dump to allow postconf to change it *) dump ~ctxt ()) (); (* Reload environment *) unload (); load ~ctxt (); (* Save environment *) print (); (* Replace data in file *) BaseFileAB.replace ~ctxt t.package.files_ab let build ~ctxt t args = BaseCustom.hook t.package.build_custom (t.build ~ctxt t.package) args let doc ~ctxt t args = BaseDoc.doc ~ctxt (join_plugin_sections (function | Doc (cs, e) -> Some (lookup_plugin_section "documentation" (s_ "build") cs.cs_name t.doc, cs, e) | _ -> None) t.package.sections) t.package args let test ~ctxt t args = BaseTest.test ~ctxt (join_plugin_sections (function | Test (cs, e) -> Some (lookup_plugin_section "test" (s_ "run") cs.cs_name t.test, cs, e) | _ -> None) t.package.sections) t.package args let all ~ctxt t args = let rno_doc = ref false in let rno_test = ref false in let arg_rest = ref [] in Arg.parse_argv ~current:(ref 0) (Array.of_list ((Sys.executable_name^" all") :: (Array.to_list args))) [ "-no-doc", Arg.Set rno_doc, s_ "Don't run doc target"; "-no-test", Arg.Set rno_test, s_ "Don't run test target"; "--", Arg.Rest (fun arg -> arg_rest := arg :: !arg_rest), s_ "All arguments for configure."; ] (failwithf (f_ "Don't know what to do with '%s'")) ""; info "Running configure step"; configure ~ctxt t (Array.of_list (List.rev !arg_rest)); info "Running build step"; build ~ctxt t [||]; (* Load setup.log dynamic variables *) BaseDynVar.init ~ctxt t.package; if not !rno_doc then begin info "Running doc step"; doc ~ctxt t [||] end else begin info "Skipping doc step" end; if not !rno_test then begin info "Running test step"; test ~ctxt t [||] end else begin info "Skipping test step" end let install ~ctxt t args = BaseCustom.hook t.package.install_custom (t.install ~ctxt t.package) args let uninstall ~ctxt t args = BaseCustom.hook t.package.uninstall_custom (t.uninstall ~ctxt t.package) args let reinstall ~ctxt t args = uninstall ~ctxt t args; install ~ctxt t args let clean, distclean = let failsafe f a = try f a with e -> warning (f_ "Action fail with error: %s") (match e with | Failure msg -> msg | e -> Printexc.to_string e) in let generic_clean ~ctxt t cstm mains docs tests args = BaseCustom.hook ~failsafe:true cstm (fun () -> (* Clean section *) List.iter (function | Test (cs, test) -> let f = try List.assoc cs.cs_name tests with Not_found -> fun ~ctxt:_ _ _ _ -> () in failsafe (f ~ctxt t.package (cs, test)) args | Doc (cs, doc) -> let f = try List.assoc cs.cs_name docs with Not_found -> fun ~ctxt:_ _ _ _ -> () in failsafe (f ~ctxt t.package (cs, doc)) args | Library _ | Object _ | Executable _ | Flag _ | SrcRepo _ -> ()) t.package.sections; (* Clean whole package *) List.iter (fun f -> failsafe (f ~ctxt t.package) args) mains) () in let clean ~ctxt t args = generic_clean ~ctxt t t.package.clean_custom t.clean t.clean_doc t.clean_test args in let distclean ~ctxt t args = (* Call clean *) clean ~ctxt t args; (* Call distclean code *) generic_clean ~ctxt t t.package.distclean_custom t.distclean t.distclean_doc t.distclean_test args; (* Remove generated source files. *) List.iter (fun fn -> if ctxt.srcfs#file_exists fn then begin info (f_ "Remove '%s'") (ctxt.srcfs#string_of_filename fn); ctxt.srcfs#remove fn end) ([BaseEnv.default_filename; BaseLog.default_filename] @ (List.rev_map BaseFileAB.to_filename t.package.files_ab)) in clean, distclean let version ~ctxt:_ (t: t) _ = print_endline t.oasis_version let update_setup_ml, no_update_setup_ml_cli = let b = ref true in b, ("-no-update-setup-ml", Arg.Clear b, s_ " Don't try to update setup.ml, even if _oasis has changed.") (* TODO: srcfs *) let default_oasis_fn = "_oasis" let update_setup_ml t = let oasis_fn = match t.oasis_fn with | Some fn -> fn | None -> default_oasis_fn in let oasis_exec = match t.oasis_exec with | Some fn -> fn | None -> "oasis" in let ocaml = Sys.executable_name in let setup_ml, args = match Array.to_list Sys.argv with | setup_ml :: args -> setup_ml, args | [] -> failwith (s_ "Expecting non-empty command line arguments.") in let ocaml, setup_ml = if Sys.executable_name = Sys.argv.(0) then (* We are not running in standard mode, probably the script * is precompiled. *) "ocaml", "setup.ml" else ocaml, setup_ml in let no_update_setup_ml_cli, _, _ = no_update_setup_ml_cli in let do_update () = let oasis_exec_version = OASISExec.run_read_one_line ~ctxt:!BaseContext.default ~f_exit_code: (function | 0 -> () | 1 -> failwithf (f_ "Executable '%s' is probably an old version \ of oasis (< 0.3.0), please update to version \ v%s.") oasis_exec t.oasis_version | 127 -> failwithf (f_ "Cannot find executable '%s', please install \ oasis v%s.") oasis_exec t.oasis_version | n -> failwithf (f_ "Command '%s version' exited with code %d.") oasis_exec n) oasis_exec ["version"] in if OASISVersion.comparator_apply (OASISVersion.version_of_string oasis_exec_version) (OASISVersion.VGreaterEqual (OASISVersion.version_of_string t.oasis_version)) then begin (* We have a version >= for the executable oasis, proceed with * update. *) (* TODO: delegate this check to 'oasis setup'. *) if Sys.os_type = "Win32" then failwithf (f_ "It is not possible to update the running script \ setup.ml on Windows. Please update setup.ml by \ running '%s'.") (String.concat " " (oasis_exec :: "setup" :: t.oasis_setup_args)) else begin OASISExec.run ~ctxt:!BaseContext.default ~f_exit_code: (fun n -> if n <> 0 then failwithf (f_ "Unable to update setup.ml using '%s', \ please fix the problem and retry.") oasis_exec) oasis_exec ("setup" :: t.oasis_setup_args); OASISExec.run ~ctxt:!BaseContext.default ocaml (setup_ml :: args) end end else failwithf (f_ "The version of '%s' (v%s) doesn't match the version of \ oasis used to generate the %s file. Please install at \ least oasis v%s.") oasis_exec oasis_exec_version setup_ml t.oasis_version in if !update_setup_ml then begin try match t.oasis_digest with | Some dgst -> if Sys.file_exists oasis_fn && dgst <> Digest.file default_oasis_fn then begin do_update (); true end else false | None -> false with e -> error (f_ "Error when updating setup.ml. If you want to avoid this error, \ you can bypass the update of %s by running '%s %s %s %s'") setup_ml ocaml setup_ml no_update_setup_ml_cli (String.concat " " args); raise e end else false let setup t = let catch_exn = ref true in let act_ref = ref (fun ~ctxt:_ _ -> failwithf (f_ "No action defined, run '%s %s -help'") Sys.executable_name Sys.argv.(0)) in let extra_args_ref = ref [] in let allow_empty_env_ref = ref false in let arg_handle ?(allow_empty_env=false) act = Arg.Tuple [ Arg.Rest (fun str -> extra_args_ref := str :: !extra_args_ref); Arg.Unit (fun () -> allow_empty_env_ref := allow_empty_env; act_ref := act); ] in try let () = Arg.parse (Arg.align ([ "-configure", arg_handle ~allow_empty_env:true configure, s_ "[options*] Configure the whole build process."; "-build", arg_handle build, s_ "[options*] Build executables and libraries."; "-doc", arg_handle doc, s_ "[options*] Build documents."; "-test", arg_handle test, s_ "[options*] Run tests."; "-all", arg_handle ~allow_empty_env:true all, s_ "[options*] Run configure, build, doc and test targets."; "-install", arg_handle install, s_ "[options*] Install libraries, data, executables \ and documents."; "-uninstall", arg_handle uninstall, s_ "[options*] Uninstall libraries, data, executables \ and documents."; "-reinstall", arg_handle reinstall, s_ "[options*] Uninstall and install libraries, data, \ executables and documents."; "-clean", arg_handle ~allow_empty_env:true clean, s_ "[options*] Clean files generated by a build."; "-distclean", arg_handle ~allow_empty_env:true distclean, s_ "[options*] Clean files generated by a build and configure."; "-version", arg_handle ~allow_empty_env:true version, s_ " Display version of OASIS used to generate this setup.ml."; "-no-catch-exn", Arg.Clear catch_exn, s_ " Don't catch exception, useful for debugging."; ] @ (if t.setup_update then [no_update_setup_ml_cli] else []) @ (BaseContext.args ()))) (failwithf (f_ "Don't know what to do with '%s'")) (s_ "Setup and run build process current package\n") in (* Instantiate the context. *) let ctxt = !BaseContext.default in (* Build initial environment *) load ~ctxt ~allow_empty:!allow_empty_env_ref (); (** Initialize flags *) List.iter (function | Flag (cs, {flag_description = hlp; flag_default = choices}) -> begin let apply ?short_desc () = var_ignore (var_define ~cli:CLIEnable ?short_desc (OASISUtils.varname_of_string cs.cs_name) (fun () -> string_of_bool (var_choose ~name:(Printf.sprintf (f_ "default value of flag %s") cs.cs_name) ~printer:string_of_bool choices))) in match hlp with | Some hlp -> apply ~short_desc:(fun () -> hlp) () | None -> apply () end | _ -> ()) t.package.sections; BaseStandardVar.init t.package; BaseDynVar.init ~ctxt t.package; if not (t.setup_update && update_setup_ml t) then !act_ref ~ctxt t (Array.of_list (List.rev !extra_args_ref)) with e when !catch_exn -> error "%s" (Printexc.to_string e); exit 1 end module BaseCompat = struct (* # 22 "src/base/BaseCompat.ml" *) (** Compatibility layer to provide a stable API inside setup.ml. This layer allows OASIS to change in between minor versions (e.g. 0.4.6 -> 0.4.7) but still provides a stable API inside setup.ml. This enables to write functions that manipulate setup_t inside setup.ml. See deps.ml for an example. The module opened by default will depend on the version of the _oasis. E.g. if we have "OASISFormat: 0.3", the module Compat_0_3 will be opened and the function Compat_0_3 will be called. If setup.ml is generated with the -nocompat, no module will be opened. @author Sylvain Le Gall *) module Compat_0_4 = struct let rctxt = ref !BaseContext.default module BaseSetup = struct module Original = BaseSetup open OASISTypes type std_args_fun = package -> string array -> unit type ('a, 'b) section_args_fun = name * (package -> (common_section * 'a) -> string array -> 'b) type t = { configure: std_args_fun; build: std_args_fun; doc: ((doc, unit) section_args_fun) list; test: ((test, float) section_args_fun) list; install: std_args_fun; uninstall: std_args_fun; clean: std_args_fun list; clean_doc: (doc, unit) section_args_fun list; clean_test: (test, unit) section_args_fun list; distclean: std_args_fun list; distclean_doc: (doc, unit) section_args_fun list; distclean_test: (test, unit) section_args_fun list; package: package; oasis_fn: string option; oasis_version: string; oasis_digest: Digest.t option; oasis_exec: string option; oasis_setup_args: string list; setup_update: bool; } let setup t = let mk_std_args_fun f = fun ~ctxt pkg args -> rctxt := ctxt; f pkg args in let mk_section_args_fun l = List.map (fun (nm, f) -> nm, (fun ~ctxt pkg sct args -> rctxt := ctxt; f pkg sct args)) l in let t' = { Original. configure = mk_std_args_fun t.configure; build = mk_std_args_fun t.build; doc = mk_section_args_fun t.doc; test = mk_section_args_fun t.test; install = mk_std_args_fun t.install; uninstall = mk_std_args_fun t.uninstall; clean = List.map mk_std_args_fun t.clean; clean_doc = mk_section_args_fun t.clean_doc; clean_test = mk_section_args_fun t.clean_test; distclean = List.map mk_std_args_fun t.distclean; distclean_doc = mk_section_args_fun t.distclean_doc; distclean_test = mk_section_args_fun t.distclean_test; package = t.package; oasis_fn = t.oasis_fn; oasis_version = t.oasis_version; oasis_digest = t.oasis_digest; oasis_exec = t.oasis_exec; oasis_setup_args = t.oasis_setup_args; setup_update = t.setup_update; } in Original.setup t' end let adapt_setup_t setup_t = let module O = BaseSetup.Original in let mk_std_args_fun f = fun pkg args -> f ~ctxt:!rctxt pkg args in let mk_section_args_fun l = List.map (fun (nm, f) -> nm, (fun pkg sct args -> f ~ctxt:!rctxt pkg sct args)) l in { BaseSetup. configure = mk_std_args_fun setup_t.O.configure; build = mk_std_args_fun setup_t.O.build; doc = mk_section_args_fun setup_t.O.doc; test = mk_section_args_fun setup_t.O.test; install = mk_std_args_fun setup_t.O.install; uninstall = mk_std_args_fun setup_t.O.uninstall; clean = List.map mk_std_args_fun setup_t.O.clean; clean_doc = mk_section_args_fun setup_t.O.clean_doc; clean_test = mk_section_args_fun setup_t.O.clean_test; distclean = List.map mk_std_args_fun setup_t.O.distclean; distclean_doc = mk_section_args_fun setup_t.O.distclean_doc; distclean_test = mk_section_args_fun setup_t.O.distclean_test; package = setup_t.O.package; oasis_fn = setup_t.O.oasis_fn; oasis_version = setup_t.O.oasis_version; oasis_digest = setup_t.O.oasis_digest; oasis_exec = setup_t.O.oasis_exec; oasis_setup_args = setup_t.O.oasis_setup_args; setup_update = setup_t.O.setup_update; } end module Compat_0_3 = struct include Compat_0_4 end end # 5668 "setup.ml" module CustomPlugin = struct (* # 22 "src/plugins/custom/CustomPlugin.ml" *) (** Generate custom configure/build/doc/test/install system @author *) open BaseEnv open OASISGettext open OASISTypes type t = { cmd_main: command_line conditional; cmd_clean: (command_line option) conditional; cmd_distclean: (command_line option) conditional; } let run = BaseCustom.run let main ~ctxt:_ t _ extra_args = let cmd, args = var_choose ~name:(s_ "main command") t.cmd_main in run cmd args extra_args let clean ~ctxt:_ t _ extra_args = match var_choose t.cmd_clean with | Some (cmd, args) -> run cmd args extra_args | _ -> () let distclean ~ctxt:_ t _ extra_args = match var_choose t.cmd_distclean with | Some (cmd, args) -> run cmd args extra_args | _ -> () module Build = struct let main ~ctxt t pkg extra_args = main ~ctxt t pkg extra_args; List.iter (fun sct -> let evs = match sct with | Library (cs, bs, lib) when var_choose bs.bs_build -> begin let evs, _ = BaseBuilt.of_library OASISHostPath.of_unix (cs, bs, lib) in evs end | Executable (cs, bs, exec) when var_choose bs.bs_build -> begin let evs, _, _ = BaseBuilt.of_executable OASISHostPath.of_unix (cs, bs, exec) in evs end | _ -> [] in List.iter (fun (bt, bnm, lst) -> BaseBuilt.register ~ctxt bt bnm lst) evs) pkg.sections let clean ~ctxt t pkg extra_args = clean ~ctxt t pkg extra_args; (* TODO: this seems to be pretty generic (at least wrt to ocamlbuild * considering moving this to BaseSetup? *) List.iter (function | Library (cs, _, _) -> BaseBuilt.unregister ~ctxt BaseBuilt.BLib cs.cs_name | Executable (cs, _, _) -> BaseBuilt.unregister ~ctxt BaseBuilt.BExec cs.cs_name; BaseBuilt.unregister ~ctxt BaseBuilt.BExecLib cs.cs_name | _ -> ()) pkg.sections let distclean ~ctxt t pkg extra_args = distclean ~ctxt t pkg extra_args end module Test = struct let main ~ctxt t pkg (cs, _) extra_args = try main ~ctxt t pkg extra_args; 0.0 with Failure s -> BaseMessage.warning (f_ "Test '%s' fails: %s") cs.cs_name s; 1.0 let clean ~ctxt t pkg _ extra_args = clean ~ctxt t pkg extra_args let distclean ~ctxt t pkg _ extra_args = distclean ~ctxt t pkg extra_args end module Doc = struct let main ~ctxt t pkg (cs, _) extra_args = main ~ctxt t pkg extra_args; BaseBuilt.register ~ctxt BaseBuilt.BDoc cs.cs_name [] let clean ~ctxt t pkg (cs, _) extra_args = clean ~ctxt t pkg extra_args; BaseBuilt.unregister ~ctxt BaseBuilt.BDoc cs.cs_name let distclean ~ctxt t pkg _ extra_args = distclean ~ctxt t pkg extra_args end end # 5800 "setup.ml" open OASISTypes;; let setup_t = { BaseSetup.configure = CustomPlugin.main { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("./configure", []))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; build = CustomPlugin.Build.main { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["build"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; test = []; doc = []; install = CustomPlugin.main { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["install"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; uninstall = CustomPlugin.main { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["uninstall"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; clean = [ CustomPlugin.clean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("./configure", []))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; CustomPlugin.Build.clean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["build"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; CustomPlugin.clean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["install"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; CustomPlugin.clean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["uninstall"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] } ]; clean_test = []; clean_doc = []; distclean = [ CustomPlugin.distclean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("./configure", []))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; CustomPlugin.Build.distclean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["build"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; CustomPlugin.distclean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["install"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] }; CustomPlugin.distclean { CustomPlugin.cmd_main = [(OASISExpr.EBool true, ("make", ["uninstall"]))]; cmd_clean = [(OASISExpr.EBool true, None)]; cmd_distclean = [(OASISExpr.EBool true, None)] } ]; distclean_test = []; distclean_doc = []; package = { oasis_version = "0.4"; ocaml_version = Some (OASISVersion.VGreaterEqual "4.00.0"); version = "1.2.9"; license = OASISLicense.DEP5License (OASISLicense.DEP5Unit { OASISLicense.license = "ZLIB"; excption = None; version = OASISLicense.NoVersion }); findlib_version = None; alpha_features = []; beta_features = []; name = "pxp"; license_file = None; copyrights = []; maintainers = []; authors = ["Gerd Stolpmann et al."]; homepage = Some "http://projects.camlcity.org/projects/pxp"; bugreports = None; synopsis = "XML parser"; description = None; tags = []; categories = []; files_ab = []; sections = [ Flag ({ cs_name = "lex"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { flag_description = Some "lex: Enable ocamllex-based lexer"; flag_default = [(OASISExpr.EBool true, true)] }); Flag ({ cs_name = "wlex"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { flag_description = Some "wlex: Enable wlex-based lexer (UTF-8)"; flag_default = [(OASISExpr.EBool true, false)] }); Flag ({ cs_name = "ulex"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { flag_description = Some "ulex: Enable ulex-based lexer (UTF-8)"; flag_default = [(OASISExpr.EBool true, false)] }); Flag ({ cs_name = "pp"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { flag_description = Some "pp: Enable the preprocessor pxp-pp"; flag_default = [(OASISExpr.EBool true, true)] }); Library ({ cs_name = "pxp-engine"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [(OASISExpr.EBool true, true)]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-engine"; bs_compiled_object = Best; bs_build_depends = [FindlibPackage ("netstring", None)]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [(OASISExpr.EBool true, true)]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-pp"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "pp", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-pp"; bs_compiled_object = Best; bs_build_depends = [ InternalLibrary "pxp"; FindlibPackage ("camlp4", None) ]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-wlex-utf8"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "wlex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-wlex-utf8"; bs_compiled_object = Best; bs_build_depends = [ InternalLibrary "pxp-engine"; FindlibPackage ("wlexing", None) ]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-ulex-utf8"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "ulex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-ulex-utf8"; bs_compiled_object = Best; bs_build_depends = [ InternalLibrary "pxp-engine"; FindlibPackage ("ulex", None) ]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88591"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88591"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-wlex"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "wlex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-wlex"; bs_compiled_object = Best; bs_build_depends = [ InternalLibrary "pxp-wlex-utf8"; InternalLibrary "pxp-lex-iso88591" ]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88592"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88592"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88593"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88593"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88594"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88594"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88595"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88595"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88596"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88596"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88597"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88597"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88598"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88598"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso88599"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso88599"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso885910"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso885910"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso885913"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso885913"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso885914"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso885914"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso885915"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso885915"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }); Library ({ cs_name = "pxp-lex-iso885916"; cs_data = PropList.Data.create (); cs_plugin_data = [] }, { bs_build = [ (OASISExpr.EBool true, false); (OASISExpr.EFlag "lex", true) ]; bs_install = [(OASISExpr.EBool true, true)]; bs_path = "src/pxp-lex-iso885916"; bs_compiled_object = Best; bs_build_depends = [InternalLibrary "pxp-engine"]; bs_build_tools = [ExternalTool "make"]; bs_interface_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${capitalize_file module}.mli" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mli" ]; origin = "${uncapitalize_file module}.mli" } ]; bs_implementation_patterns = [ { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${capitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".ml" ]; origin = "${uncapitalize_file module}.ml" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${capitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mll" ]; origin = "${uncapitalize_file module}.mll" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("capitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${capitalize_file module}.mly" }; { OASISSourcePatterns.Templater.atoms = [ OASISSourcePatterns.Templater.Text ""; OASISSourcePatterns.Templater.Expr (OASISSourcePatterns.Templater.Call ("uncapitalize_file", OASISSourcePatterns.Templater.Ident "module")); OASISSourcePatterns.Templater.Text ".mly" ]; origin = "${uncapitalize_file module}.mly" } ]; bs_c_sources = []; bs_data_files = []; bs_findlib_extra_files = []; bs_ccopt = [(OASISExpr.EBool true, [])]; bs_cclib = [(OASISExpr.EBool true, [])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; bs_nativeopt = [(OASISExpr.EBool true, [])] }, { lib_modules = []; lib_pack = false; lib_internal_modules = []; lib_findlib_parent = None; lib_findlib_name = None; lib_findlib_directory = None; lib_findlib_containers = [] }) ]; disable_oasis_section = []; conf_type = (`Configure, "custom", Some "0.4"); conf_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, Some (("make", ["-s"; "postconf"]))) ] }; build_type = (`Build, "custom", Some "0.4"); build_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; install_type = (`Install, "custom", Some "0.4"); install_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; uninstall_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; clean_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; distclean_custom = { pre_command = [(OASISExpr.EBool true, None)]; post_command = [(OASISExpr.EBool true, None)] }; plugins = []; schema_data = PropList.Data.create (); plugin_data = [] }; oasis_fn = Some "_oasis"; oasis_version = "0.4.8"; oasis_digest = Some "\203\236\239=g\167w\207\185\253\028g\178%\227\253"; oasis_exec = None; oasis_setup_args = []; setup_update = false };; let setup () = BaseSetup.setup setup_t;; # 8959 "setup.ml" let setup_t = BaseCompat.Compat_0_4.adapt_setup_t setup_t open BaseCompat.Compat_0_4 (* OASIS_STOP *) let () = setup ();; pxp-1.2.9/README0000644000175000017500000004433013055274551011651 0ustar gerdgerd****************************************************************************** README - PXP, the XML parser for O'Caml ****************************************************************************** ============================================================================== Abstract ============================================================================== PXP is an XML parser for O'Caml. It represents the parsed document either as tree or as stream of events. In tree mode, it is possible to validate the XML document against a DTD. The acronym PXP means Polymorphic XML Parser. This name reflects the ability to create XML trees with polymorphic type parameters. ============================================================================== Download ============================================================================== You can download PXP as gzip'ed tarball [1]. The parser needs the Ocamlnet [2] package (0.9.3). Note that PXP requires O'Caml 3.09 or newer. Information about the latest development version is available here [3]. ============================================================================== PXP Reference ============================================================================== The manual is included in the distribution as bunch of HTML files. An online version can be found here [4]. ============================================================================== Author, Credits, Copying ============================================================================== PXP has been written by Gerd Stolpmann [5]; it contains contributions by Claudio Sacerdoti Coen. You may copy it as you like, you may use it even for commercial purposes as long as the license conditions are respected, see the file LICENSE coming with the distribution. It allows almost everything. Thanks also to Alain Frisch and Haruo Hosoya for discussions and bug reports. ============================================================================== Description ============================================================================== PXP is a validating XML parser for O'Caml [6]. It strictly complies to the XML-1.0 [7] standard. The parser is simple to call, usually only one statement (function call) is sufficient to parse an XML document and to represent it as object tree. Once the document is parsed, it can be accessed using a class interface. The interface allows arbitrary access including transformations. One of the features of the document representation is its polymorphic nature; it is simple to add custom methods to the document classes. Furthermore, the parser can be configured such that different XML elements are represented by objects created from different classes. This is a very powerful feature, because it simplifies the structure of programs processing XML documents. Note that the class interface does not comply to the DOM standard. It was not a development goal to realize a standard API (industrial developers can this much better than I); however, the API is powerful enough to be considered as equivalent with DOM. More important, the interface is compatible with the XML information model required by many XML-related standards. There is now also an event-oriented interface comparable to SAX. PXP also supports the popular pull parsing model. ------------------------------------------------------------------------------ Detailed feature list ------------------------------------------------------------------------------ - The XML instance is validated against the DTD; any violation of a validation constraint leads to the rejection of the instance. The validator has been carefully implemented, and conforms strictly to the standard. If needed, it is also possible to run the parser in a well-formedness mode. - If possible, the validator applies a deterministic finite automaton to validate the content models. This ensures that validation can always be performed in linear time. However, in the case that the content models are not deterministic, the parser uses a backtracking algorithm which can be much slower. - It is also possible to reject non-deterministic content models. - In particular, the validator also checks the complicated rules whether parentheses are properly nested with respect to entities, and whether the standalone declaration is satisfied. On demand, it is checked whether the IDREF attributes only refer to existing nodes. - Entity references are automatically resolved while the XML text is being scanned. It is not possible to recognize in the object tree where a referenced entity begins or ends; the object tree only represents the logical structure. - External entities are loaded using a configurable resolver infrastructure. It is possible to connect the parser with an arbitrary XML source. - The parser can read XML text encoded in a variety of character sets. Independent of this, it is possible to choose the encoding of the internal representation of the tree nodes; the parser automatically converts the input text to this encoding. Currently, the parser supports UTF-8 and ISO-8859-1 as internal encodings. - The interface of the parser has been designed such that it is best integrated into the language O'Caml. The first goal was simplicity of usage which is achieved by many convenience methods and functions, and by allowing the user to select which parts of the XML text are actually represented in the tree. For example, it is possible to store processing instructions as tree nodes, but the parser can also be configured such that these instructions are put into hashtables. The information model is compatible with the requirements of XML-related standards such as XPath. - In particular, the node tree can optionally contain or leave out processing instructions and comments. It is also possible to generate a "super root" object which is the parent of the root element. The attributes of elements are normally not stored as nodes, but it is possible to get them wrapped into nodes. - The powerful type system of O'Caml makes it possible that the parser supports polymorphism based on the element types, i.e. it can be configured that the parser selects different classes to represent different element types. Note that no generator is needed for this feature. - There is also an interface for DTDs; you can parse and access sequences of declarations. The declarations are fully represented as recursive O'Caml values. - Since PXP 1.1, the parser supports namespaces. This has been implemented using a technique called "prefix normalization", i.e. while parsing the namespace prefixes are changed (in a configurable way) such that they become unique in the whole document (or document domain). This is again a solution that is different from other parsers, but it allows a very convenient style of processing namespaces while sticking strictly to the XML standard. Another advantage of this solution is that DTDs can refer to namespaces in a transparent way, i.e. it is possible to validate a document against a DTD that uses different namespace prefixes for the same namespaces. ------------------------------------------------------------------------------ Recent Changes ------------------------------------------------------------------------------ - 1.2.9: Build with OCaml-4.04.0 - 1.2.8: Build against ocamlnet-4.1. Support -safe-string - 1.2.7: tweaking support for oasis. - 1.2.6: Adding _oasis file. - 1.2.5: Build against ocamlnet-4. - 1.2.4: Fixed bug in namespace-aware parsing (thanks to ygrek and Thomas Leonard) - 1.2.3: Ported to OCaml-4.00 - 1.2.2: Fixing the interaction of catalog and file resolution. Fix because of a change in Ocamlnet-3.3.1 - 1.2.1: Revised documentation Addition: Pxp_event.unwrap_document Addition: Pxp_dtd.Entity.lookup Addition: node method entity_id Addition: Pxp_event.close_entities Removed: Pxp_core_types_type, Pxp_type_anchor. Pxp_core_types has now three submodules A, S, I taking over the roles Removed: E_pinstr_member. Instead, E_pinstr events are emitted Renaming, and addition: `Entry_content has been renamed to `Entry_element_content. A new `Entry_content with different semantics has been added, now conforming to a standard production. Improvement: The parser also accepts a BOM as UTF-8 sequence. Also, the autodetection of the encoding for UTF-16 has been enhanced Fix: Pxp_marshal module also keeps namespace scope objects Addition: method lexbuf in lexer_obj - 1.2.0test*: New ~minimization option for the [write] and [display] methods (user wish). Improvement: better control what is printed as DTD for document#write and #display Fix: [Pxp_document.liquefy] terminates now when invoked only on a subtree of a document Cleaned up the code a bit so fewer warnings are emitted in the build. Ported pxp-pp to O'Caml 3.10 - 1.1.96: Works now for O'Caml 3.09, too. Fix: The "root element check" is disabled in Pxp_dtd. It did not work together with namespaces. Pxp_validate: Fix for namespace mode - 1.1.95: Addition of ulex lexing. Fix in Pxp_reader.combine. Revised namespace handling: There are now namespace_scope objects keeping the scoping structure of the namespaces. The namespace_info stuff has been removed. The "display" methods can print XML while respecting the scoping structure. New exceptions Namespace_not_managed, Namespace_prefix_not_managed, Namespace_not_in_scope (all replacing Not_found). Methods of namespace_manager may raise these exceptions. The event-based representation of XML is now symmetrical to the tree-based representation, such that it is possible to convert one representation into the other without loss. The type of events had to be changed to achieve this effect. The new module Pxp_event contains functions for the event-based representation. Addition of pxp-pp, the PXP preprocessor. This release requires Ocamlnet 0.98. You should also install ulex. There are no longer precompiled wlex lexers (use ulex instead). - 1.1.94.2: Again fixes for the combination of 3.07/wlex - 1.1.94.1: Fixes for 3.07 concerning the pregenerated wlexers. - New: Pxp_document.build_node_tree - 1.1.94: The Pxp_reader module has been completely rewritten. This fixes some problems with relative URLs. - Pxp_yacc has been split up into four modules: Pxp_tree_parser contains now the parser API returning object trees, Pxp_dtd_parser is the parser API returning DTDs, Pxp_ev_parser is the event-based API, and Pxp_core_parser is the core of the parser. Pxp_yacc is still available as compatibility API. As part of the module redesign, Pxp_types includes now parts of its interface from Pxp_core_types_type. I hope this style of programming is comprehensible. - I think PXP can now compiled with CVS releases of O'Caml. - It is now possible to turn warnings into errors. - The event-based parser can now preprocess namespaces. Furthermore, there are normalization filters. - 1.1.93: This is a bugfix release. Sometimes files were not closed in previous versions, but now they are. There were debug statements in the pull parser code, I have removed them. Finally, some errors in the Makefiles have been corrected. - 1.1.92: The whole lexing stuff has been restructured. There is a new tool, lexpp, that generates the lexers from only five files. Furthermore, much more 8 bit character sets are now supported as internal encodings. In previous versions of PXP, the internal representation of the XML trees was restricted to either UTF-8 or ISO-8859-1. Now, a number of additional encodings are supported, including the whole ISO-8859 series. Bugfix: If the processing instruction occurs in the middle of the XML document, version 1.1.91 will immediately stop parsing, and ignore the rest of the file. This is now fixed. - 1.1.91: The curly braces can now even be used inside attributes, and escape from normal XML parsing. There is a new entry point Entry_expr for event-based parsing that expects either a single element, a single processing instruction, or a single comment, or whitespace. This allows more fine-grained control of what is parsed. There is now a "pull parser". In contrast to the "push parser" introduced in 1.1.90, the calling order of parser and parser user have been inverted, i.e. the user calls the parser to get ("pull") the next event instead of letting the parser call back a user function ("push"). An interesting application is that O'Caml's lazy streams can be used to analyze events. An example can be found in examles/pullparser. Pull parsing is not yet well-tested! - 1.1.90: This version introduces a new event-based interface in Pxp_yacc. For start tags, end tags, data strings, and several other things that are found in the XML source so-called events are generated, and a user function is called for every event. See the directory examples/eventparser for examples. Another innovation is support for curly braces as escape characters. Inside elements, the left curly brace escapes from XML parsing and starts a foreign parser until the matching right curly brace is found: ... { foreign syntax } ... The curly braces are borrowed from the XQuery draft standard. They cannot yet be used inside attribute values. Curly braces are mostly useful in conjunction with event-based parsing, because it is not yet possible to include the "value" of the curly brace expression into XML trees. It is even possible to call the XML parser from the foreign parser as subparser. However, there not yet enough entry points for the event-based parser (e.g. you cannot parse just the following processing instruction, only misc* element misc* or whole documents are possible). A long-standing bug has been found in the entity layer. When an external entity A opens an external entity B, and B opens C, relative paths of C have been interpreted wrong. - Changed in 1.1.5: A packaging error in pxp-wlex has been corrected. (This is the only change.) - Changed in 1.1.4: This is a bigger bug fix release that addresses the following problems: The parser does no longer show very bad performance when large data nodes without line feeds are parsed. Another performance problem with bigger DTDs has been solved, too. Especially, the XHTML DTD can now be parsed quite quickly. The interface Pxp_dtd.Entity has been extended, it is now possible to access more properties of entities than before. Pxp_marshal has been revised. It is now possible to recode the input or output stream on the fly in order to change the character encoding. Furthermore, the functions relocate_subtree and relocate_document allows one to marshal an XML tree or a document, and to read the marshaled data immediately to create a copy of the original structure. Some errors have been fixed in from_file. Especially, this function will no longer raise the exception Malformed_URL if the current working directory happens to be "/". Pxp_document.strip_whitespace implements xml:space now correctly. In previous versions, xml:space='default' was ignored when it occurred inside an element with xml:space='preserve'. Now the inner xml:space='default' overrides the outer xml:space='preserve' as defined in the XML standard. - Changed in 1.1.3: This release fixes a single problem occurring when PXP is compiled with installed netstring-0.10. (There is not any problem with netstring-0.91.) - Changed in 1.1.2: Improved write method for whole documents. It can now also output a reference to an external DTD. PXP can be compiled with O'Caml 3.04. - Changed in 1.1.1: Minor changes for O'Caml 3.03-alpha. The interfaces have not been modified. - Changed in 1.1: The parser supports now namespaces. Extended/updated Pxp_document interface. There is now a separate class for every node type. It is now clear which node methods validate and which do not validate. The node tree can now be simpler modified (insert/delete). It is now possible to start in well-formedness mode and validate the XML tree later (as a whole, or partially). New functions for tree normalization, and whitespace stripping. The implementation of Pxp_document has been updated, too. There are now many virtual classes, one class for one task. The attribute representation has been improved. The overall size of the document tree has been reduced. The parser is better in counting lines. The option errors_with_line_numbers could be removed because the parser is now fast enough that it does make sense to always count lines. There are now string pools that can save memory in some situations. New module Pxp_marshal allows marshalling of XML trees over channels (faster than writing the tree and reparsing it). For the most important entity functions there is an interface Pxp_document.Entity. Although there are many extensions, the parser has been sped up. The parser has been divided up into several packages, and the directory structure of the distribution has been cleaned up. It is possible to chose among several lexical analyzers. One of them bases on Alain Frisch's wlex patch, which reduces the size of executables if a UTF-8 parser is needed. The parser works under Cygwin. Of course several bug fixes. Note that most bugs have been added in the development cycle between 1.0 and 1.1; only very few problems have been detected in the 1.0 release. I hope that 1.1 has similar quality. -------------------------- [1] see http://download.camlcity.org/download/pxp-1.1.6.tar.gz [2] see /projects/ocamlnet.html [3] see /projects/pxp.html [4] see /projects/dl/pxp-1.1.6/doc/manual/html/index.html [5] see mailto:gerd@gerd-stolpmann.de [6] see http://caml.inria.fr/ [7] see http://www.w3.org/TR/1998/REC-xml-19980210.html pxp-1.2.9/INSTALL0000644000175000017500000002053213055274551012020 0ustar gerdgerd****************************************************************************** INSTALL - PXP, the XML parser for O'Caml ****************************************************************************** ============================================================================== The "pxp" package ============================================================================== ------------------------------------------------------------------------------ Prerequisites ------------------------------------------------------------------------------ PXP requires that the ocamlnet library [1] is already installed (version 4.1 required). PXP works only with O'Caml >= 4.01. The installation procedure defined in the Makefile requires findlib [2] to work [3]. PXP may be optionally compiled with support for Alain Frisch's patch of ocamllex called "wlex" [4]. There is now also support for ulex, Alain's Unicode-aware replacement for ocamllex (same link), which is simpler to build and now highly recommended. ------------------------------------------------------------------------------ Configuration ------------------------------------------------------------------------------ Beginning with PXP 1.1 it is necessary to configure the parser! Configuration is very simple, and in almost all cases it is sufficient to do ./configure in the top level directory of the distribution. It is possible to turn some options on or off using the -with-xxx and -without-xxx arguments. You can get a list by invoking ./configure -help: - -with-lex Enables the lexical analyzers ("lexers") generated by the ocamllex tool. You can specify which ocamllex-based lexers are created with the -lexlist option (see below). - -with-wlex Enables the lexical analyzer that works for UTF-8 as internal encoding, and that is based on Alain Frisch's wlex tool. It is relatively small and almost as fast as the ocamllex-based lexers. I recommend it if it is ok to install another library (wlex). - -with-wlex-compat Creates a compatibility package pxp-wlex that includes lexers for UTF8 and ISO-8859-1 (may be required to build old software) - -with-ulex Enables the lexical analyzer that works for UTF-8 as internal encoding, and that is based on Alain Frisch's ulex tool. It is relatively small, but a bit slower than the ocamllex-based lexers. ulex will supersede wlex soon. ulex is required for the preprocessor (see below). - -with-pp Enables the PXP preprocessor (installed as package pxp-pp). See the file PREPROCESSOR for details. The preprocessor requires ulex. - -lexlist Specifies the character encodings to support by the ocamllex- based lexers. You need only the encodings you are going to use for the internal representation of the XML data in memory. It is not necessary to mention a character set here if you only want to read an external file. Note that utf8 is also provided by both -with-wlex and -with-ulex, and it is reasonable to omit it here if one of the mentioned options is in effect. Note that you need at least one lexical analyzer to use PXP as parser. ------------------------------------------------------------------------------ Compilation ------------------------------------------------------------------------------ The Makefile defines the following goals: - make all compiles with the bytecode compiler and creates various bytecode archives (suffix .cma) and some bytecode objects (suffix .cmo) in the directories below src. - make opt compiles with the native compiler and creates various native archives (suffixes .cmxa and .a) and some native objects (suffixes .cmx and .o) in the directories below src. ------------------------------------------------------------------------------ Installation ------------------------------------------------------------------------------ The Makefile defines the following goals: - make install installs the bytecode archives, the interface definitions, and if present, the native archives in the default location of findlib. Up to five packages may be installed: pxp, pxp-engine, pxp-lex-iso88591, pxp-lex-utf8, pxp-wlex. - make uninstall removes any of the mentioned packages Note: Previous versions of PXP had a compatibility API for the old "markup" distribution. This API is no longer supported. Upgrading to the PXP API is not very difficult. ------------------------------------------------------------------------------ Usage with the help of "findlib" ------------------------------------------------------------------------------ You can refer to the parser as the findlib package "pxp": ocamlfind ocamlc -package pxp ... Using "pxp" includes as much features of the parser as available, i.e. everything that has been configured. This may result in large executables. One possibility to reduce the code size is to specify Netstring-related predicates (e.g. netstring_only_iso); see the documentation of Netstring. Note that these predicates reduce the number of conversion tables for character encodings, and this means that not every character encoding of external files can be processed. Another way of reducing the size of executables is to link only selected parts of PXP. It is possible to specify which PXP subpackage is linked; for example, ocamlfind ocamlc -package pxp-engine,pxp-lex-iso88591 ... will only use "pxp-engine" (the core package) and the lexical analyzer "pxp-lex-iso88591", even if you have installed more PXP packages. ------------------------------------------------------------------------------ Linking with the archives directly ------------------------------------------------------------------------------ The following archives and objects may be used: - pxp_engine.cma: The core of PXP (always needed) - pxp_lex_iso88591.cma: The ocamllex-based lexical analyzer if you want to internally represent texts as ISO-8859-1. - pxp_lex_link_iso88591.cmo: Registers pxp_lex_iso88591 as lexer. - pxp_lex_utf8.cma: The ocamllex-based lexical analyzer if you want to internally represent texts as UTF-8. - pxp_lex_link_utf8.cmo: Registers pxp_lex_utf8 as lexer. - pxp_wlex.cma: The wlex-based lexical analyzer that works for both ISO-8859-1 and UTF-8 and results in smaller executables (but needs wlex). - pxp_wlex_link.cmo: Registers pxp_wlex as lexer. - pxp_top.cmo: Loading this module into the toploop installs several printers for PXP types. Note that you need at least one of the lexical analyzers if you want to parse XML texts. You do not need them if your program uses other features of PXP but not parsing. The archives containing the lexers are only linked into your executable if you also link the corresponding "register module". ============================================================================== The examples ============================================================================== In the "examples" directory you find several applications of PXP. They require that PXP has been installed using findlib. See the Makefiles in the directories for descriptions of "make" goals. ============================================================================== Trouble shooting ============================================================================== ------------------------------------------------------------------------------ Solaris ------------------------------------------------------------------------------ The "make" utility of Solaris does not work properly enough; there is a bug in it that prevents the so-called suffix rules from being recognized. There are two solutions: - Install GNU make and use it instead of Solaris make. This is the recommended way to solve the problem, as GNU make can process almost every Makefile from open source projects, and you will never have problems with building software again. - Add the following lines to Makefile.rules: %.cmx: %.ml $(OCAMLOPT) -c $< %.cmo: %.ml $(OCAMLC) -c $< %.cmi: %.mli $(OCAMLC) -c $< %.ml: %.mll ocamllex $< -------------------------- [1] see /projects/ocamlnet.html [2] see /projects/findlib.html [3] Findlib is a package manager, see the file ABOUT-FINDLIB. [4] see http://www.eleves.ens.fr:8080/home/frisch/soft pxp-1.2.9/ABOUT-FINDLIB0000644000175000017500000000453713055274551012640 0ustar gerdgerd****************************************************************************** ABOUT-FINDLIB - Package manager for O'Caml ****************************************************************************** ============================================================================== Abstract ============================================================================== The findlib library provides a scheme to manage reusable software components (packages), and includes tools that support this scheme. Packages are collections of OCaml modules for which metainformation can be stored. The packages are kept in the filesystem hierarchy, but with strict directory structure. The library contains functions to look the directory up that stores a package, to query metainformation about a package, and to retrieve dependency information about multiple packages. There is also a tool that allows the user to enter queries on the command-line. In order to simplify compilation and linkage, there are new frontends of the various OCaml compilers that can directly deal with packages. Together with the packages metainformation is stored. This includes a version string, the archives the package consists of, and additional linker options. Packages can also be dependent on other packages. There is a query which finds out all predecessors of a list of packages and sorts them topologically. The new compiler frontends do this implicitly. Metainformation can be conditional, i.e. depend on a set of predicates. This is mainly used to be able to react on certain properties of the environment, such as if the bytecode or the native compiler is invoked, if the application is multi-threaded, and a few more. If the new compiler frontends are used, most predicates are found out automatically. There is special support for scripts. A new directive, "#require", loads packages into scripts. Of course, this works only with newly created toploops which include the findlib library. ============================================================================== Where to get findlib ============================================================================== The manual of findlib is available online [1]. You can download findlib here [2]. -------------------------- [1] see /projects/findlib.html [2] see http://download.camlcity.org/download/findlib-1.2.8.tar.gz pxp-1.2.9/_oasis0000644000175000017500000000640113055274551012166 0ustar gerdgerdOASISFormat: 0.4 Name: pxp Version: 1.2.9 Synopsis: XML parser Authors: Gerd Stolpmann et al. ConfType: custom (0.4) BuildType: custom (0.4) InstallType: custom (0.4) BuildTools: make License: ZLIB OCamlVersion: >= 4.00.0 Homepage: http://projects.camlcity.org/projects/pxp XCustomConf: ./configure PostConfCommand: make -s postconf XCustomBuild: make build XCustomInstall: make install XCustomUninstall: make uninstall Flag "lex" Description: lex: Enable ocamllex-based lexer Default: true Flag "wlex" Description: wlex: Enable wlex-based lexer (UTF-8) Default: false Flag "ulex" Description: ulex: Enable ulex-based lexer (UTF-8) Default: false Flag "pp" Description: pp: Enable the preprocessor pxp-pp Default: true Library "pxp" Path: src/pxp Build: true BuildDepends: pxp-engine Library "pxp-engine" Path: src/pxp-engine BuildDepends: netstring Build: true Library "pxp-pp" Path: src/pxp-pp BuildDepends: pxp BuildDepends+: camlp4 Build: false if flag(pp) Build: true Library "pxp-wlex" Path: src/pxp-wlex BuildDepends: pxp-wlex-utf8, pxp-lex-iso88591 Build: false if flag(wlex) Build: true Library "pxp-wlex-utf8" Path: src/pxp-wlex-utf8 BuildDepends: pxp-engine, wlexing Build: false if flag(wlex) Build: true Library "pxp-ulex-utf8" Path: src/pxp-ulex-utf8 BuildDepends: pxp-engine, ulex Build: false if flag(ulex) Build: true # assuming the default -lexlist Library "pxp-lex-iso88591" Path: src/pxp-lex-iso88591 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88592" Path: src/pxp-lex-iso88592 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88593" Path: src/pxp-lex-iso88593 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88594" Path: src/pxp-lex-iso88594 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88595" Path: src/pxp-lex-iso88595 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88596" Path: src/pxp-lex-iso88596 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88597" Path: src/pxp-lex-iso88597 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88598" Path: src/pxp-lex-iso88598 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso88599" Path: src/pxp-lex-iso88599 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso885910" Path: src/pxp-lex-iso885910 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso885913" Path: src/pxp-lex-iso885913 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso885914" Path: src/pxp-lex-iso885914 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso885915" Path: src/pxp-lex-iso885915 BuildDepends: pxp-engine Build: false if flag(lex) Build: true Library "pxp-lex-iso885916" Path: src/pxp-lex-iso885916 BuildDepends: pxp-engine Build: false if flag(lex) Build: true pxp-1.2.9/configure0000755000175000017500000003004013055274551012671 0ustar gerdgerd#! /bin/sh # $Id$ # defaults: with_lex=1 with_wlex=1 with_wlex_compat=1 with_ulex=1 with_pp=1 lexlist="utf8,iso88591,iso88592,iso88593,iso88594,iso88595,iso88596,iso88597,iso88598,iso88599,iso885910,iso885913,iso885914,iso885915,iso885916" version="1.2.9" exec_suffix="" help_lex="Enable/disable ocamllex-based lexical analyzer for the -lexlist encodings" help_wlex="Enable/disable wlex-based lexical analyzer for UTF-8" help_wlex_compat="Enable/disable wlex-style compatibility package for UTF-8 and ISO-8859-1" help_ulex="Enable/disable ulex-based lexical analyzer for UTF-8" help_pp="Enable/disable the build of the preprocessor (pxp-pp)" options="lex wlex wlex_compat ulex pp" lexlist_options="utf8 usascii iso88591 iso88592 iso88593 iso88594 iso88595 iso88596 iso88597 iso88598 iso88599 iso885910 iso885913 iso885914 iso885915 iso885916 koi8r windows1250 windows1251 windows1252 windows1253 windows1254 windows1255 windows1256 windows1257 windows1258 cp437 cp737 cp775 cp850 cp852 cp855 cp856 cp857 cp860 cp861 cp862 cp863 cp864 cp865 cp866 cp869 cp874 cp1006 macroman" print_options () { for opt in $options; do e="o=\$with_$opt" eval "$e" uopt=`echo $opt | sed -e 's/_/-/g'` if [ $o -gt 0 ]; then echo " -with-$uopt" else echo " -without-$uopt" fi done printf ' -lexlist %s\n' "$lexlist" } usage () { formatted_lexlist="" n=0 for lexname in $lexlist_options; do formatted_lexlist=`printf '%s%-12s' "$formatted_lexlist" $lexname` n=`expr $n + 1` if [ $n -eq 5 ]; then n=0 formatted_lexlist=`printf '%s\n ' "$formatted_lexlist"` fi done cat <<_EOF_ >&2 usage: ./configure [ options ] _EOF_ for opt in $options; do e="help=\$help_$opt" eval "$e" uopt=`echo $opt | sed -e 's/_/-/g'` echo "-with-$uopt:" >&2 echo "-without-$uopt:" >&2 echo " $help" >&2 done cat <<_EOF_ >&2 -lexlist : Supported encodings are: $formatted_lexlist all: selects all of them Defaults are: _EOF_ print_options >&2 exit 1 } check_opt () { for x in $options; do if [ "$x" = "$1" ]; then return 0 fi done echo "Unknown option: $1" >&2 exit 1 } while [ "$#" -gt 0 ]; do case "$1" in -with-*) opt=`echo "$1" | sed -e 's/-with-//' -e 's/-/_/g'` check_opt "$opt" eval "with_$opt=1" shift ;; -enable-*) opt=`echo "$1" | sed -e 's/-enable-//' -e 's/-/_/g'` check_opt "$opt" eval "with_$opt=1" shift ;; -without-*) opt=`echo "$1" | sed -e 's/-without-//' -e 's/-/_/g'` check_opt "$opt" eval "with_$opt=0" shift ;; -disable-*) opt=`echo "$1" | sed -e 's/-disable-//' -e 's/-/_/g'` check_opt "$opt" eval "with_$opt=0" shift ;; -lexlist) if [ "$2" = "all" ]; then lexlist="$lexlist_options" else lexlist="$2" fi shift shift ;; -prefix|--prefix) echo "[prefix ignored]"; shift 2 ;; --prefix=) echo "[prefix ignored]"; shift ;; -destdir|--destdir) echo "[destdir ignored]"; shift 2 ;; --destdir=) echo "[destdir ignored]"; shift ;; -version*) echo "$version" exit 0 ;; *) usage esac done ###################################################################### # Check ocamlfind printf "%s" "Checking for ocamlfind... " if ocamlfind query stdlib >/dev/null 2>/dev/null; then echo "found" else echo "not found" echo "Sorry, installation is not possible without ocamlfind (findlib)!" echo "Make sure that ocamlfind is in your PATH, or download findlib" echo "from www.ocaml-programming.de" exit 1 fi ###################################################################### # Check camlp4 version printf "%s" "Checking for camlp4... " if camlp4; then if camlp4 -loaded-modules >/dev/null 2>/dev/null; then echo "3.10 style" camlp4_style="310" camlp4_opts="-package camlp4 -syntax camlp4o -ppopt pa_extend.cmo -ppopt q_MLast.cmo" else echo "3.09 style" camlp4_style="309" camlp4_opts="-package camlp4 -syntax camlp4o -ppopt pa_extend.cmo -ppopt q_MLast.cmo -ppopt -loc -ppopt loc" fi else echo "not found" echo "Make sure the camlp4 command is in your PATH" exit 1 fi ###################################################################### # Check ocamllex.opt printf "%s" "Checking for ocamllex.opt..." r=`ocamllex.opt -help 2>&1` lex_opt="" case "$r" in *usage*) echo "found" lex_opt=".opt" ;; *) echo "not found" ;; esac ###################################################################### # Check netstring printf "%s" "Checking for netstring... " if ocamlfind query netstring >/dev/null 2>/dev/null; then echo "found" else echo "not found" echo "Sorry, installation is not possible without netstring!" echo "Please download netstring from www.ocaml-programming.de" exit 1 fi printf "%s" "Checking for netunidata... " if ocamlfind query netunidata >/dev/null 2>/dev/null; then echo "found" netunidata="netunidata" else echo "not found" netunidata="" fi ###################################################################### # Check wlex if [ $with_wlex_compat -gt 0 ]; then if [ $with_wlex -eq 0 ]; then echo "WARNING! -with-wlex-compat implies -with-wlex" with_wlex=1 fi if [ $with_lex -eq 0 ]; then echo "WARNING! -with-wlex-compat implies -with-lex for ISO-8859-1" with_lex=1 lexlist="iso88591" fi if grep iso88591 >/dev/null 2>/dev/null </dev/null 2>/dev/null; then printf "%s" "library found, " out=`wlex -help 2>&1` case "$out" in usage*) echo "generator found" ;; *) echo "generator not found" echo "*** It is now required that the full 'wlex' tool is installed, sorry." echo "wlex support is disabled" with_wlex=0 with_wlex_compat=0 ;; esac else echo "not found" echo "wlex support is disabled" with_wlex=0 with_wlex_compat=0 fi fi ###################################################################### # ulex if [ $with_ulex -gt 0 ]; then printf "%s" "Checking for ulex... " if ocamlfind query ulex >/dev/null 2>/dev/null; then echo "found" else echo "not found" echo "ulex support is disabled" with_ulex=0 fi fi # If ulex not found/disabled, also disable pxp-pp: if [ $with_ulex -eq 0 ]; then with_pp=0 fi ###################################################################### # Check Lexing.lexbuf type printf "%s" "Checking Lexing.lexbuf type... " cat <tmp.ml open Lexing let lb = from_string "";; let _ = lb.lex_mem;; let _ = lb.lex_start_p;; let _ = lb.lex_curr_p;; EOF lexbuf_307="" if ocamlc -c tmp.ml >/dev/null 2>/dev/null; then echo "new style" lexbuf_307="-D LEXBUF_307" else echo "old style" fi rm -f tmp.* ###################################################################### # Check type of camlp4 locations printf "%s" "Checking type of camlp4 location... " cat <tmp.ml open Stdpp;; raise_with_loc (0,0) Not_found;; EOF if ocamlc -c -I +camlp4 tmp.ml >/dev/null 2>/dev/null; then echo "old style" camlp4_loc="" else echo "new style" camlp4_loc="-ppopt -DOCAML_NEW_LOC" fi rm -f tmp.* ###################################################################### # immutable strings printf "%s" "Checking for -safe-string... " string_opts="" if ocamlc -safe-string; then echo "yes" string_opts="-safe-string" else echo "no" fi ###################################################################### # Check cygwin printf "%s" "Checking for cygwin... " u=`uname` case "$u" in CYGWIN*) echo "found" exec_suffix=".exe" ;; *) echo "not found" ;; esac ###################################################################### # Summary echo echo "Effective options:" print_options echo pkglist="pxp pxp-engine" if [ $with_pp -gt 0 ]; then pkglist="$pkglist pxp-pp" fi genpkglist="" # Generated packages allgenpkglist="" # Package names that can possibly be generated lexlist=`echo "$lexlist" | sed -e 's/,/ /g'` # reqall: the predecessor list for package "pxp": reqall="pxp-engine" for lexname in $lexlist; do include=1 if [ "$lexname" = "utf8" ]; then if [ $with_wlex -gt 0 -o $with_ulex -gt 0 ]; then # Leave UTF-8 out include=0 fi fi if [ $include -gt 0 ]; then reqall="$reqall pxp-lex-$lexname" fi genpkglist="$genpkglist pxp-lex-$lexname" done if [ $with_wlex -gt 0 -a $with_ulex -eq 0 ]; then reqall="$reqall pxp-wlex-utf8" fi if [ $with_ulex -gt 0 ]; then reqall="$reqall pxp-ulex-utf8" fi if [ $with_wlex -gt 0 ]; then genpkglist="$genpkglist pxp-wlex-utf8" fi if [ $with_wlex_compat -gt 0 ]; then genpkglist="$genpkglist pxp-wlex" fi if [ $with_ulex -gt 0 ]; then genpkglist="$genpkglist pxp-ulex-utf8" fi for lexname in $lexlist_options; do allgenpkglist="$allgenpkglist pxp-lex-$lexname" done allgenpkglist="$allgenpkglist pxp-wlex pxp-wlex-utf8" ###################################################################### # Write META for pkglist for pkg in $pkglist; do echo "Writing src/$pkg/META" sed -e "s/@VERSION@/$version/g" \ -e "s/@REQALL@/$reqall/g" \ src/$pkg/META.in >src/$pkg/META done ###################################################################### # Write META and Makefile for lexlist for enc in $lexlist; do pkg="pxp-lex-$enc" echo "Writing gensrc/$pkg/META and Makefile" mkdir -p "gensrc/$pkg" touch "gensrc/$pkg/gen_dir" sed -e "s/@VERSION@/$version/g" \ -e "s/@ENCNAME@/$enc/g" \ gensrc/pxp-lex-pattern/META.in >gensrc/$pkg/META echo "# THIS IS A GENERATED FILE - DO NOT EDIT MANUALLY!" >gensrc/$pkg/Makefile sed -e "s/@ENCNAME@/$enc/g" \ gensrc/pxp-lex-pattern/Makefile.in >>gensrc/$pkg/Makefile done ###################################################################### # Write META for wlex if [ $with_wlex -gt 0 ]; then pkg="pxp-wlex-utf8" echo "Writing gensrc/$pkg/META" sed -e "s/@VERSION@/$version/g" \ -e "s/@ENCNAME@/$enc/g" \ gensrc/$pkg/META.in >gensrc/$pkg/META fi if [ $with_wlex_compat -gt 0 ]; then pkg="pxp-wlex" echo "Writing gensrc/$pkg/META" sed -e "s/@VERSION@/$version/g" \ -e "s/@ENCNAME@/$enc/g" \ gensrc/$pkg/META.in >gensrc/$pkg/META fi ###################################################################### # Write META for ulex if [ $with_ulex -gt 0 ]; then pkg="pxp-ulex-utf8" echo "Writing gensrc/$pkg/META" sed -e "s/@VERSION@/$version/g" \ -e "s/@ENCNAME@/$enc/g" \ gensrc/$pkg/META.in >gensrc/$pkg/META fi ###################################################################### # Write Makefile.conf echo "Writing Makefile.conf" cat <<_EOF_ >Makefile.conf VERSION = $version PKGLIST = $pkglist GENPKGLIST = $genpkglist ALLGENPKGLIST = $allgenpkglist EXEC_SUFFIX = $exec_suffix LEXBUF_307 = $lexbuf_307 LEX_OPT = $lex_opt CAMLP4_LOC = $camlp4_loc CAMLP4_STYLE = $camlp4_style CAMLP4_OPTS = $camlp4_opts NETUNIDATA = $netunidata STRING_OPTS = $string_opts _EOF_ ###################################################################### # make oasis happy: setup.save will be picked up by "make postconf" # and will be appended to setup.data. That way the config update # will reach oasis. rm -f setup.save echo "pkg_version=\"$version\"" >>setup.save echo "prefix=\"\"" >>setup.save echo "destdir=\"\"" >>setup.save for opt in $options; do e="o=\$with_$opt" eval "$e" if [ $o -gt 0 ]; then echo "$opt=\"true\"" >>setup.save else echo "$opt=\"false\"" >>setup.save fi done ###################################################################### # Finish echo echo "You can now compile PXP by invoking" echo " make all" echo "for the bytecode compiler, and optionally by invoking" echo " make opt" echo "for the native-code compiler (if supported on your architecture)." echo "Finally, a" echo " make install" echo "will install the package." pxp-1.2.9/doc/0000755000175000017500000000000013055274551011532 5ustar gerdgerdpxp-1.2.9/doc/design.txt0000644000175000017500000003506613055274551013556 0ustar gerdgerdNOTE: The following text is partly out of date, but not fully. ------------------------------------------------ -*- indented-text -*- Some Notes About the Design: ---------------------------------------------------------------------- ---------------------------------------------------------------------- Compilation ---------------------------------------------------------------------- Compilation is non-trivial because: - The lexer and parser generators ocamlllex resp. ocamlyacc normally create code such that the parser module precedes the lexer module. THIS design requires that the lexer layer precedes the entity layer which precedes the parser layer, because the parsing results modify the behaviour of the lexer and entity layers. There is no way to get around this because of the nature of XML. So the dependency relation of the lexer and the parser is modified; in particular the "token" type that is normally defined by the generated parser is moved to a common predecessor of both lexer and parser. - Another modification of the standard way of handling parsers is that the parser is turned into an object. This is necessary because the whole parser is polymorphic, i.e. there is a type parameter (the type of the node extension). ...................................................................... First some modules are generated as illustrated by the following diagram: markup_yacc.mly | | \|/ \|/ [ocamlyacc, 1] V V markup_yacc.mli markup_yacc.ml | --> renamed into markup_yacc.ml0 [awk, 2] \|/ | V \|/ [sed, 3] markup_yacc_token.mlf V | | markup_yacc.ml markup_lexer_types_ | | shadow.mli | | | markup_lexer_types_ \|/ [sed, \|/ | shadow.ml V 4] V | | markup_lexer_types.mli | | [sed, 4] \|/ \|/ V V markup_lexer_types.ml markup_yacc_shadow.mli | \|/ [replaces, 5] V markup_yacc.mli markup_lexers.mll | \|/ [ocamllex, 6] V markup_lexers.ml Notes: (1) ocamlyacc generates both a module and a module interface. The module is postprocessed in step (3). The interface cannot be used, but it contains the definition of the "token" type. This definition is extracted in step (2). The interface is completely replaced in step (5) by a different file. (2) An "awk" script extracts the definition of the type "token". "token" is created by ocamlyacc upon the %token directives in markup_yacc.mly, and normally "token" is defined in the module generated by ocamlyacc. This turned out not to be useful as the module dependency must be that the lexer is an antecedent of the parser and not vice versa (as usually), so the "token" type is "moved" to the module Markup_lexer_types which is an antecedent of both the lexer and the parser. (3) A "sed" script turns the generated parser into an object. This is rather simple; some "let" definitions must be rewritten as "val" definitions, the other "let" definitions as "method" definitions. The parser object is needed because the whole parser has a polymorphic type parameter. (4) The implementation and definition of Markup_lexer_types are both generated by inserting the "token" type definition (in markup_lexer_types.mlf) into two pattern files, markup_lexer_types_shadow.ml resp. -.mli. The point of insertion is marked by the string INCLUDE_HERE. (5) The generated interface of the Markup_yacc module is replaced by a hand-written file. (6) ocamllex generates the lexer; this process is not patched in any way. ...................................................................... After the additional modules have been generated, compilation proceeds in the usual manner. ---------------------------------------------------------------------- Hierarchy of parsing layers: ---------------------------------------------------------------------- From top to bottom: - Parser: Markup_yacc + gets input stream from the main entity object + checks most of the grammar + creates the DTD object as side-effect + creates the element tree as side-effect + creates further entity objects that are entered into the DTD - Entity layer: Markup_entity + gets input stream from the lexers, or another entity object + handles entity references: if a reference is encountered the input stream is redirected such that the tokens come from the referenced entity object + handles conditional sections - Lexer layer: Markup_lexers + gets input from lexbuffers created by resolvers + different lexers for different lexical contexts + a lexer returns pairs (token,lexid), where token is the scanned token, and lexid is the name of the lexer that must be used for the next token - Resolver layer: Markup_entity + a resolver creates the lexbuf from some character source + a resolver recodes the input and handles the encoding scheme ---------------------------------------------------------------------- The YACC based parser ---------------------------------------------------------------------- ocamlyacc allows it to pass an arbitrary 'next_token' function to the parsing functions. We always use 'en # next_token()' where 'en' is the main entity object representing the main file to be parsed. The parser is not functional, but uses mainly side-effects to accumulate the structures that have been recognized. This is very important for the entity definitions, because once an entity definition has been found there may be a reference to it which is handled by the entity layer (which is below the yacc layer). This means that such a definition modifies the token source of the parser, and this can only be handled by side-effects (at least in a sensible manner; a purely functional parser would have to pass unresolved entity references to its caller, which would have to resolve the reference and to re-parse the whole document!). Note that also element definitions profit from the imperative style of the parser; an element instance can be validated directly once the end tag has been read in. ---------------------------------------------------------------------- The entity layer ---------------------------------------------------------------------- The parser gets the tokens from the main entity object. This object controls the underlying lexing mechanism (see below), and already interprets the following: - Conditional sections (if they are allowed in this entity): The structures and are recognized and interpreted. This would be hard to realize by the yacc parser, because: - INCLUDE and IGNORE are not recognized as lexical keywords but as names. This means that the parser cannot select different rules for them. - The text after IGNORE requires a different lexical handling. - Entity references: &name; and %name; The named entity is looked up and the input source is redirected to it, i.e. if the main entity object gets the message 'next_token' this message is forwarded to the referenced entity. (This entity may choose to forward the message again to a third entity, and so on.) There are some fine points: - It is okay that redirection happens at token level, not at character level: + General entities must always match the 'content' production, and because of this they must always consist of a whole number of tokens. + If parameter entities are resolved, the XML specification states that a space character is inserted before and after the replacement text. This also means that such entities always consists of a whole number of tokens. - There are some "nesting constraints": + General entities must match the 'content' production. Because of this, the special token Begin_entity is inserted before the first token of the entity, and End_entity is inserted just before the Eof token. The brace Begin_entity...End_entity is recognized by the yacc parser, but only in the 'content' production. + External parameter entities must match 'extSubsetDecl'. Again, Begin_entity and End_entity tokens embrace the inner token stream. The brace Begin_entity...End_entity is recognized by the yacc parser at the appropriate position. (As general and parameter entities are used in different contexts (document vs. DTD), both kinds of entities can use the same brace Begin_entity...End_entity.) + TODO: The constraints for internal parameter entities are not yet checked. - Recursive references can be detected because entities must be opened before the 'next_token' method can be invoked. ---------------------------------------------------------------------- The lexer layer ---------------------------------------------------------------------- There are five main lexers, and a number of auxiliary lexers. The five main lexers are: - Document (function scan_document): Scans an XML document outside the DTD and outside the element instance. - Content (function scan_content): Scans an element instance, but not within tags. - Within_tag (function scan_within_tag): Scans within <...>, i.e. a tag denoting an element instance. - Document_type (function scan_document_type): Scans after . - Declaration (function scan_declaration): Scans sequences of declarations Why several lexers? Because there are different lexical rules in these five regions of an XML document. Every lexer not only produces tokens, but also the name of the next lexer to use. For example, if the Document lexer scans " ]> ∅ - This is illegal, and the presence of an empty Begin_entity/End_entity pair helps to recognize this. pxp-1.2.9/doc/README0000644000175000017500000004433013055274551012416 0ustar gerdgerd****************************************************************************** README - PXP, the XML parser for O'Caml ****************************************************************************** ============================================================================== Abstract ============================================================================== PXP is an XML parser for O'Caml. It represents the parsed document either as tree or as stream of events. In tree mode, it is possible to validate the XML document against a DTD. The acronym PXP means Polymorphic XML Parser. This name reflects the ability to create XML trees with polymorphic type parameters. ============================================================================== Download ============================================================================== You can download PXP as gzip'ed tarball [1]. The parser needs the Ocamlnet [2] package (0.9.3). Note that PXP requires O'Caml 3.09 or newer. Information about the latest development version is available here [3]. ============================================================================== PXP Reference ============================================================================== The manual is included in the distribution as bunch of HTML files. An online version can be found here [4]. ============================================================================== Author, Credits, Copying ============================================================================== PXP has been written by Gerd Stolpmann [5]; it contains contributions by Claudio Sacerdoti Coen. You may copy it as you like, you may use it even for commercial purposes as long as the license conditions are respected, see the file LICENSE coming with the distribution. It allows almost everything. Thanks also to Alain Frisch and Haruo Hosoya for discussions and bug reports. ============================================================================== Description ============================================================================== PXP is a validating XML parser for O'Caml [6]. It strictly complies to the XML-1.0 [7] standard. The parser is simple to call, usually only one statement (function call) is sufficient to parse an XML document and to represent it as object tree. Once the document is parsed, it can be accessed using a class interface. The interface allows arbitrary access including transformations. One of the features of the document representation is its polymorphic nature; it is simple to add custom methods to the document classes. Furthermore, the parser can be configured such that different XML elements are represented by objects created from different classes. This is a very powerful feature, because it simplifies the structure of programs processing XML documents. Note that the class interface does not comply to the DOM standard. It was not a development goal to realize a standard API (industrial developers can this much better than I); however, the API is powerful enough to be considered as equivalent with DOM. More important, the interface is compatible with the XML information model required by many XML-related standards. There is now also an event-oriented interface comparable to SAX. PXP also supports the popular pull parsing model. ------------------------------------------------------------------------------ Detailed feature list ------------------------------------------------------------------------------ - The XML instance is validated against the DTD; any violation of a validation constraint leads to the rejection of the instance. The validator has been carefully implemented, and conforms strictly to the standard. If needed, it is also possible to run the parser in a well-formedness mode. - If possible, the validator applies a deterministic finite automaton to validate the content models. This ensures that validation can always be performed in linear time. However, in the case that the content models are not deterministic, the parser uses a backtracking algorithm which can be much slower. - It is also possible to reject non-deterministic content models. - In particular, the validator also checks the complicated rules whether parentheses are properly nested with respect to entities, and whether the standalone declaration is satisfied. On demand, it is checked whether the IDREF attributes only refer to existing nodes. - Entity references are automatically resolved while the XML text is being scanned. It is not possible to recognize in the object tree where a referenced entity begins or ends; the object tree only represents the logical structure. - External entities are loaded using a configurable resolver infrastructure. It is possible to connect the parser with an arbitrary XML source. - The parser can read XML text encoded in a variety of character sets. Independent of this, it is possible to choose the encoding of the internal representation of the tree nodes; the parser automatically converts the input text to this encoding. Currently, the parser supports UTF-8 and ISO-8859-1 as internal encodings. - The interface of the parser has been designed such that it is best integrated into the language O'Caml. The first goal was simplicity of usage which is achieved by many convenience methods and functions, and by allowing the user to select which parts of the XML text are actually represented in the tree. For example, it is possible to store processing instructions as tree nodes, but the parser can also be configured such that these instructions are put into hashtables. The information model is compatible with the requirements of XML-related standards such as XPath. - In particular, the node tree can optionally contain or leave out processing instructions and comments. It is also possible to generate a "super root" object which is the parent of the root element. The attributes of elements are normally not stored as nodes, but it is possible to get them wrapped into nodes. - The powerful type system of O'Caml makes it possible that the parser supports polymorphism based on the element types, i.e. it can be configured that the parser selects different classes to represent different element types. Note that no generator is needed for this feature. - There is also an interface for DTDs; you can parse and access sequences of declarations. The declarations are fully represented as recursive O'Caml values. - Since PXP 1.1, the parser supports namespaces. This has been implemented using a technique called "prefix normalization", i.e. while parsing the namespace prefixes are changed (in a configurable way) such that they become unique in the whole document (or document domain). This is again a solution that is different from other parsers, but it allows a very convenient style of processing namespaces while sticking strictly to the XML standard. Another advantage of this solution is that DTDs can refer to namespaces in a transparent way, i.e. it is possible to validate a document against a DTD that uses different namespace prefixes for the same namespaces. ------------------------------------------------------------------------------ Recent Changes ------------------------------------------------------------------------------ - 1.2.9: Build with OCaml-4.04.0 - 1.2.8: Build against ocamlnet-4.1. Support -safe-string - 1.2.7: tweaking support for oasis. - 1.2.6: Adding _oasis file. - 1.2.5: Build against ocamlnet-4. - 1.2.4: Fixed bug in namespace-aware parsing (thanks to ygrek and Thomas Leonard) - 1.2.3: Ported to OCaml-4.00 - 1.2.2: Fixing the interaction of catalog and file resolution. Fix because of a change in Ocamlnet-3.3.1 - 1.2.1: Revised documentation Addition: Pxp_event.unwrap_document Addition: Pxp_dtd.Entity.lookup Addition: node method entity_id Addition: Pxp_event.close_entities Removed: Pxp_core_types_type, Pxp_type_anchor. Pxp_core_types has now three submodules A, S, I taking over the roles Removed: E_pinstr_member. Instead, E_pinstr events are emitted Renaming, and addition: `Entry_content has been renamed to `Entry_element_content. A new `Entry_content with different semantics has been added, now conforming to a standard production. Improvement: The parser also accepts a BOM as UTF-8 sequence. Also, the autodetection of the encoding for UTF-16 has been enhanced Fix: Pxp_marshal module also keeps namespace scope objects Addition: method lexbuf in lexer_obj - 1.2.0test*: New ~minimization option for the [write] and [display] methods (user wish). Improvement: better control what is printed as DTD for document#write and #display Fix: [Pxp_document.liquefy] terminates now when invoked only on a subtree of a document Cleaned up the code a bit so fewer warnings are emitted in the build. Ported pxp-pp to O'Caml 3.10 - 1.1.96: Works now for O'Caml 3.09, too. Fix: The "root element check" is disabled in Pxp_dtd. It did not work together with namespaces. Pxp_validate: Fix for namespace mode - 1.1.95: Addition of ulex lexing. Fix in Pxp_reader.combine. Revised namespace handling: There are now namespace_scope objects keeping the scoping structure of the namespaces. The namespace_info stuff has been removed. The "display" methods can print XML while respecting the scoping structure. New exceptions Namespace_not_managed, Namespace_prefix_not_managed, Namespace_not_in_scope (all replacing Not_found). Methods of namespace_manager may raise these exceptions. The event-based representation of XML is now symmetrical to the tree-based representation, such that it is possible to convert one representation into the other without loss. The type of events had to be changed to achieve this effect. The new module Pxp_event contains functions for the event-based representation. Addition of pxp-pp, the PXP preprocessor. This release requires Ocamlnet 0.98. You should also install ulex. There are no longer precompiled wlex lexers (use ulex instead). - 1.1.94.2: Again fixes for the combination of 3.07/wlex - 1.1.94.1: Fixes for 3.07 concerning the pregenerated wlexers. - New: Pxp_document.build_node_tree - 1.1.94: The Pxp_reader module has been completely rewritten. This fixes some problems with relative URLs. - Pxp_yacc has been split up into four modules: Pxp_tree_parser contains now the parser API returning object trees, Pxp_dtd_parser is the parser API returning DTDs, Pxp_ev_parser is the event-based API, and Pxp_core_parser is the core of the parser. Pxp_yacc is still available as compatibility API. As part of the module redesign, Pxp_types includes now parts of its interface from Pxp_core_types_type. I hope this style of programming is comprehensible. - I think PXP can now compiled with CVS releases of O'Caml. - It is now possible to turn warnings into errors. - The event-based parser can now preprocess namespaces. Furthermore, there are normalization filters. - 1.1.93: This is a bugfix release. Sometimes files were not closed in previous versions, but now they are. There were debug statements in the pull parser code, I have removed them. Finally, some errors in the Makefiles have been corrected. - 1.1.92: The whole lexing stuff has been restructured. There is a new tool, lexpp, that generates the lexers from only five files. Furthermore, much more 8 bit character sets are now supported as internal encodings. In previous versions of PXP, the internal representation of the XML trees was restricted to either UTF-8 or ISO-8859-1. Now, a number of additional encodings are supported, including the whole ISO-8859 series. Bugfix: If the processing instruction occurs in the middle of the XML document, version 1.1.91 will immediately stop parsing, and ignore the rest of the file. This is now fixed. - 1.1.91: The curly braces can now even be used inside attributes, and escape from normal XML parsing. There is a new entry point Entry_expr for event-based parsing that expects either a single element, a single processing instruction, or a single comment, or whitespace. This allows more fine-grained control of what is parsed. There is now a "pull parser". In contrast to the "push parser" introduced in 1.1.90, the calling order of parser and parser user have been inverted, i.e. the user calls the parser to get ("pull") the next event instead of letting the parser call back a user function ("push"). An interesting application is that O'Caml's lazy streams can be used to analyze events. An example can be found in examles/pullparser. Pull parsing is not yet well-tested! - 1.1.90: This version introduces a new event-based interface in Pxp_yacc. For start tags, end tags, data strings, and several other things that are found in the XML source so-called events are generated, and a user function is called for every event. See the directory examples/eventparser for examples. Another innovation is support for curly braces as escape characters. Inside elements, the left curly brace escapes from XML parsing and starts a foreign parser until the matching right curly brace is found: ... { foreign syntax } ... The curly braces are borrowed from the XQuery draft standard. They cannot yet be used inside attribute values. Curly braces are mostly useful in conjunction with event-based parsing, because it is not yet possible to include the "value" of the curly brace expression into XML trees. It is even possible to call the XML parser from the foreign parser as subparser. However, there not yet enough entry points for the event-based parser (e.g. you cannot parse just the following processing instruction, only misc* element misc* or whole documents are possible). A long-standing bug has been found in the entity layer. When an external entity A opens an external entity B, and B opens C, relative paths of C have been interpreted wrong. - Changed in 1.1.5: A packaging error in pxp-wlex has been corrected. (This is the only change.) - Changed in 1.1.4: This is a bigger bug fix release that addresses the following problems: The parser does no longer show very bad performance when large data nodes without line feeds are parsed. Another performance problem with bigger DTDs has been solved, too. Especially, the XHTML DTD can now be parsed quite quickly. The interface Pxp_dtd.Entity has been extended, it is now possible to access more properties of entities than before. Pxp_marshal has been revised. It is now possible to recode the input or output stream on the fly in order to change the character encoding. Furthermore, the functions relocate_subtree and relocate_document allows one to marshal an XML tree or a document, and to read the marshaled data immediately to create a copy of the original structure. Some errors have been fixed in from_file. Especially, this function will no longer raise the exception Malformed_URL if the current working directory happens to be "/". Pxp_document.strip_whitespace implements xml:space now correctly. In previous versions, xml:space='default' was ignored when it occurred inside an element with xml:space='preserve'. Now the inner xml:space='default' overrides the outer xml:space='preserve' as defined in the XML standard. - Changed in 1.1.3: This release fixes a single problem occurring when PXP is compiled with installed netstring-0.10. (There is not any problem with netstring-0.91.) - Changed in 1.1.2: Improved write method for whole documents. It can now also output a reference to an external DTD. PXP can be compiled with O'Caml 3.04. - Changed in 1.1.1: Minor changes for O'Caml 3.03-alpha. The interfaces have not been modified. - Changed in 1.1: The parser supports now namespaces. Extended/updated Pxp_document interface. There is now a separate class for every node type. It is now clear which node methods validate and which do not validate. The node tree can now be simpler modified (insert/delete). It is now possible to start in well-formedness mode and validate the XML tree later (as a whole, or partially). New functions for tree normalization, and whitespace stripping. The implementation of Pxp_document has been updated, too. There are now many virtual classes, one class for one task. The attribute representation has been improved. The overall size of the document tree has been reduced. The parser is better in counting lines. The option errors_with_line_numbers could be removed because the parser is now fast enough that it does make sense to always count lines. There are now string pools that can save memory in some situations. New module Pxp_marshal allows marshalling of XML trees over channels (faster than writing the tree and reparsing it). For the most important entity functions there is an interface Pxp_document.Entity. Although there are many extensions, the parser has been sped up. The parser has been divided up into several packages, and the directory structure of the distribution has been cleaned up. It is possible to chose among several lexical analyzers. One of them bases on Alain Frisch's wlex patch, which reduces the size of executables if a UTF-8 parser is needed. The parser works under Cygwin. Of course several bug fixes. Note that most bugs have been added in the development cycle between 1.0 and 1.1; only very few problems have been detected in the 1.0 release. I hope that 1.1 has similar quality. -------------------------- [1] see http://download.camlcity.org/download/pxp-1.1.6.tar.gz [2] see /projects/ocamlnet.html [3] see /projects/pxp.html [4] see /projects/dl/pxp-1.1.6/doc/manual/html/index.html [5] see mailto:gerd@gerd-stolpmann.de [6] see http://caml.inria.fr/ [7] see http://www.w3.org/TR/1998/REC-xml-19980210.html pxp-1.2.9/doc/INSTALL0000644000175000017500000002053213055274551012565 0ustar gerdgerd****************************************************************************** INSTALL - PXP, the XML parser for O'Caml ****************************************************************************** ============================================================================== The "pxp" package ============================================================================== ------------------------------------------------------------------------------ Prerequisites ------------------------------------------------------------------------------ PXP requires that the ocamlnet library [1] is already installed (version 4.1 required). PXP works only with O'Caml >= 4.01. The installation procedure defined in the Makefile requires findlib [2] to work [3]. PXP may be optionally compiled with support for Alain Frisch's patch of ocamllex called "wlex" [4]. There is now also support for ulex, Alain's Unicode-aware replacement for ocamllex (same link), which is simpler to build and now highly recommended. ------------------------------------------------------------------------------ Configuration ------------------------------------------------------------------------------ Beginning with PXP 1.1 it is necessary to configure the parser! Configuration is very simple, and in almost all cases it is sufficient to do ./configure in the top level directory of the distribution. It is possible to turn some options on or off using the -with-xxx and -without-xxx arguments. You can get a list by invoking ./configure -help: - -with-lex Enables the lexical analyzers ("lexers") generated by the ocamllex tool. You can specify which ocamllex-based lexers are created with the -lexlist option (see below). - -with-wlex Enables the lexical analyzer that works for UTF-8 as internal encoding, and that is based on Alain Frisch's wlex tool. It is relatively small and almost as fast as the ocamllex-based lexers. I recommend it if it is ok to install another library (wlex). - -with-wlex-compat Creates a compatibility package pxp-wlex that includes lexers for UTF8 and ISO-8859-1 (may be required to build old software) - -with-ulex Enables the lexical analyzer that works for UTF-8 as internal encoding, and that is based on Alain Frisch's ulex tool. It is relatively small, but a bit slower than the ocamllex-based lexers. ulex will supersede wlex soon. ulex is required for the preprocessor (see below). - -with-pp Enables the PXP preprocessor (installed as package pxp-pp). See the file PREPROCESSOR for details. The preprocessor requires ulex. - -lexlist Specifies the character encodings to support by the ocamllex- based lexers. You need only the encodings you are going to use for the internal representation of the XML data in memory. It is not necessary to mention a character set here if you only want to read an external file. Note that utf8 is also provided by both -with-wlex and -with-ulex, and it is reasonable to omit it here if one of the mentioned options is in effect. Note that you need at least one lexical analyzer to use PXP as parser. ------------------------------------------------------------------------------ Compilation ------------------------------------------------------------------------------ The Makefile defines the following goals: - make all compiles with the bytecode compiler and creates various bytecode archives (suffix .cma) and some bytecode objects (suffix .cmo) in the directories below src. - make opt compiles with the native compiler and creates various native archives (suffixes .cmxa and .a) and some native objects (suffixes .cmx and .o) in the directories below src. ------------------------------------------------------------------------------ Installation ------------------------------------------------------------------------------ The Makefile defines the following goals: - make install installs the bytecode archives, the interface definitions, and if present, the native archives in the default location of findlib. Up to five packages may be installed: pxp, pxp-engine, pxp-lex-iso88591, pxp-lex-utf8, pxp-wlex. - make uninstall removes any of the mentioned packages Note: Previous versions of PXP had a compatibility API for the old "markup" distribution. This API is no longer supported. Upgrading to the PXP API is not very difficult. ------------------------------------------------------------------------------ Usage with the help of "findlib" ------------------------------------------------------------------------------ You can refer to the parser as the findlib package "pxp": ocamlfind ocamlc -package pxp ... Using "pxp" includes as much features of the parser as available, i.e. everything that has been configured. This may result in large executables. One possibility to reduce the code size is to specify Netstring-related predicates (e.g. netstring_only_iso); see the documentation of Netstring. Note that these predicates reduce the number of conversion tables for character encodings, and this means that not every character encoding of external files can be processed. Another way of reducing the size of executables is to link only selected parts of PXP. It is possible to specify which PXP subpackage is linked; for example, ocamlfind ocamlc -package pxp-engine,pxp-lex-iso88591 ... will only use "pxp-engine" (the core package) and the lexical analyzer "pxp-lex-iso88591", even if you have installed more PXP packages. ------------------------------------------------------------------------------ Linking with the archives directly ------------------------------------------------------------------------------ The following archives and objects may be used: - pxp_engine.cma: The core of PXP (always needed) - pxp_lex_iso88591.cma: The ocamllex-based lexical analyzer if you want to internally represent texts as ISO-8859-1. - pxp_lex_link_iso88591.cmo: Registers pxp_lex_iso88591 as lexer. - pxp_lex_utf8.cma: The ocamllex-based lexical analyzer if you want to internally represent texts as UTF-8. - pxp_lex_link_utf8.cmo: Registers pxp_lex_utf8 as lexer. - pxp_wlex.cma: The wlex-based lexical analyzer that works for both ISO-8859-1 and UTF-8 and results in smaller executables (but needs wlex). - pxp_wlex_link.cmo: Registers pxp_wlex as lexer. - pxp_top.cmo: Loading this module into the toploop installs several printers for PXP types. Note that you need at least one of the lexical analyzers if you want to parse XML texts. You do not need them if your program uses other features of PXP but not parsing. The archives containing the lexers are only linked into your executable if you also link the corresponding "register module". ============================================================================== The examples ============================================================================== In the "examples" directory you find several applications of PXP. They require that PXP has been installed using findlib. See the Makefiles in the directories for descriptions of "make" goals. ============================================================================== Trouble shooting ============================================================================== ------------------------------------------------------------------------------ Solaris ------------------------------------------------------------------------------ The "make" utility of Solaris does not work properly enough; there is a bug in it that prevents the so-called suffix rules from being recognized. There are two solutions: - Install GNU make and use it instead of Solaris make. This is the recommended way to solve the problem, as GNU make can process almost every Makefile from open source projects, and you will never have problems with building software again. - Add the following lines to Makefile.rules: %.cmx: %.ml $(OCAMLOPT) -c $< %.cmo: %.ml $(OCAMLC) -c $< %.cmi: %.mli $(OCAMLC) -c $< %.ml: %.mll ocamllex $< -------------------------- [1] see /projects/ocamlnet.html [2] see /projects/findlib.html [3] Findlib is a package manager, see the file ABOUT-FINDLIB. [4] see http://www.eleves.ens.fr:8080/home/frisch/soft pxp-1.2.9/doc/ABOUT-FINDLIB0000644000175000017500000000453713055274551013405 0ustar gerdgerd****************************************************************************** ABOUT-FINDLIB - Package manager for O'Caml ****************************************************************************** ============================================================================== Abstract ============================================================================== The findlib library provides a scheme to manage reusable software components (packages), and includes tools that support this scheme. Packages are collections of OCaml modules for which metainformation can be stored. The packages are kept in the filesystem hierarchy, but with strict directory structure. The library contains functions to look the directory up that stores a package, to query metainformation about a package, and to retrieve dependency information about multiple packages. There is also a tool that allows the user to enter queries on the command-line. In order to simplify compilation and linkage, there are new frontends of the various OCaml compilers that can directly deal with packages. Together with the packages metainformation is stored. This includes a version string, the archives the package consists of, and additional linker options. Packages can also be dependent on other packages. There is a query which finds out all predecessors of a list of packages and sorts them topologically. The new compiler frontends do this implicitly. Metainformation can be conditional, i.e. depend on a set of predicates. This is mainly used to be able to react on certain properties of the environment, such as if the bytecode or the native compiler is invoked, if the application is multi-threaded, and a few more. If the new compiler frontends are used, most predicates are found out automatically. There is special support for scripts. A new directive, "#require", loads packages into scripts. Of course, this works only with newly created toploops which include the findlib library. ============================================================================== Where to get findlib ============================================================================== The manual of findlib is available online [1]. You can download findlib here [2]. -------------------------- [1] see /projects/findlib.html [2] see http://download.camlcity.org/download/findlib-1.2.8.tar.gz pxp-1.2.9/doc/SPEC0000644000175000017500000002177613055274551012224 0ustar gerdgerd****************************************************************************** Notes on the XML specification ****************************************************************************** ============================================================================== This document ============================================================================== There are some points in the XML specification which are ambiguous. The following notes discuss these points, and describe how this parser behaves. ============================================================================== Conditional sections and the token ]]> ============================================================================== It is unclear what happens if an ignored section contains the token ]]> at places where it is normally allowed, i.e. within string literals and comments, e.g. --> ]]> On the one hand, the production rule of the XML grammar does not treat such tokens specially. Following the grammar, already the first ]]> ends the conditional section and the other tokens are included into the DTD. On the other hand, we can read: "Like the internal and external DTD subsets, a conditional section may contain one or more complete declarations, comments, processing instructions, or nested conditional sections, intermingled with white space" (XML 1.0 spec, section 3.4). Complete declarations and comments may contain ]]>, so this is contradictory to the grammar. The intention of conditional sections is to include or exclude the section depending on the current replacement text of a parameter entity. Almost always such sections are used as in (or "IGNORE") This means that if it is possible to include a section it must also be legal to ignore the same section. This is a strong indication that the token ]]> must not count as section terminator if it occurs in a string literal or comment. This parser implements the latter. ============================================================================== Conditional sections and the inclusion of parameter entities ============================================================================== It is unclear what happens if an ignored section contains a reference to a parameter entity. In most cases, this is not problematic because nesting of parameter entities must respect declaration braces. The replacement text of parameter entities must either contain a whole number of declarations or only inner material of one declaration. Almost always it does not matter whether these references are resolved or not (the section is ignored). But there is one case which is not explicitly specified: Is it allowed that the replacement text of an entity contains the end marker ]]> of an ignored conditional section? Example: "> must be contained in the same entity as the corresponding of declarations). So it is possible to conclude that ]]> may be in another entity. Of course, there are many arguments not to allow such constructs: The resulting code is incomprehensive, and parsing takes longer (especially if the entities are external). I think the best argument against this kind of XML is that the XML spec is not detailed enough, as it contains no rules where entity references should be recognized and where not. For example: "> "> Which token ]]> counts? From a logical point of view, the ]]> in the third line ends the conditional section. As already pointed out, the XML spec permits the interpretation that ]]> is recognized even in string literals, and this may be also true if it is "imported" from a separate entity; and so the first ]]> denotes the end of the section. As a practical solution, this parser does not expand parameter entities in ignored sections. Furthermore, it is also not allowed that the ending ]]> of ignored or included sections is contained in a different entity than the starting %ext; %ent; "ext" contains: "> Here, the reference %ent; would be illegal if the standalone declaration is strictly interpreted. This parser handles the references %ent; and %ext; equivalently which means that %ent; is allowed, but the element type "el" is treated as externally declared. General entities can occur within the DTD, but they can only be contained in the default value of attributes, or in the definition of other general entities. The latter can be ignored, because the check will be repeated when the entities are expanded. Though, general entities occurring in default attribute values are actually checked at the moment when the default is used in an element instance. General entities occurring in the document body are always checked. NDATA entities can occur in ENTITY attribute values; either in the element instance or in the default declaration. Both cases are checked. pxp-1.2.9/doc/manual/0000755000175000017500000000000013055274552013010 5ustar gerdgerdpxp-1.2.9/doc/manual/Makefile0000644000175000017500000000575613055274551014464 0ustar gerdgerddefault: odoc .PHONY: odoc odoc: html/pic/done cd ../../src/pxp-engine && $(MAKE) doc rm -rf html/ref mkdir -p html/ref cp style.css html/ref ocamldoc -v -g ../../tools/src/odoc/chtml.cmo \ -t "PXP Reference" \ -I ../../src/pxp-engine \ -load ../../src/pxp-engine/pxp_engine.dump \ -d html/ref \ -colorize-code \ -css-style style.css -intro index.txt clean: rm -rf html man ps rm -f src/readme.ent CLEAN: clean distclean: rm -f src/*~ rm -f *~ rm -f ps/*.aux ps/*.dvi ps/*.log ps/*.tex #----------------------------------------------------------------- # The following is for the old manual. No longer updated, and totally # out of date. # Note: The following Makefile works for _me_. The stable releases of # PXP contain an already built manual, so you do not need this Makefile. # The following software is required: # - jade/sp # - docbook 3.x (Davenport Group) # - docbook stylesheets by Normal Walsh # # Furthermore, you need an ocaml toploop "ocamlfattop" that can be # built by: # ocamlfind ocamlmktop -o ocamlfattop -package str,unix,findlib -linkpkg DOCBOOK_HTML = /usr/share/sgml/docbkdsl/html DOCBOOK_PRINT = /usr/share/sgml/docbkdsl/print SRC = $(PWD)/src SOURCE = ../../src/pxp-engine/pxp_document.mli \ ../../src/pxp-engine/pxp_types.mli UPSOURCE = $(shell for x in $(SOURCE); do echo "../$$x"; done) .PHONY: html ps html: html/book1.htm html/pic/done ps: ps/pxp.ps ps/pic/done src/readme.ent: ../../examples/readme/to_html.ml src/getcode.ml <../../examples/readme/to_html.ml >src/readme.ent src/yacc.mli.ent: ../../src/pxp-engine/pxp_yacc.mli src/getcode.ml <../../src/pxp-engine/pxp_yacc.mli >src/yacc.mli.ent src/dtd.mli.ent: ../../src/pxp-engine/pxp_dtd.mli src/getcode.ml <../../src/pxp-engine/pxp_dtd.mli >src/dtd.mli.ent src/extracted.ent: $(SOURCE) mkdir -p src/extracted rm -f src/extracted/* (cd src; ./extract.ml $(UPSOURCE)) html/book1.htm: src/*.sgml src/readme.ent src/yacc.mli.ent src/dtd.mli.ent src/extracted.ent mkdir -p html cp src/markup.css html; \ cd html; \ rm -f *.htm*; \ jade -t sgml -D$(DOCBOOK_HTML) -D$(SRC) -ihtml markup.sgml; \ true touch html/TIMESTAMP html/pic/done: src/pic/*.fig mkdir -p html/pic l=`cd src/pic; echo *.fig`; \ for x in $$l; do fig2dev -L gif src/pic/$$x html/pic/`basename $$x .fig`.gif; done touch html/pic/done #man: src/findlib_reference.xml # mkdir -p man # cd man; \ # rm -f *.[0-9]; \ # db2man <../src/findlib_reference.xml ps/markup.tex: src/*.sgml src/readme.ent src/yacc.mli.ent src/dtd.mli.ent mkdir -p ps cd ps; \ jade -t tex -D$(DOCBOOK_PRINT) -D$(SRC) markup.sgml; \ true ps/markup.dvi: ps/markup.tex ps/pic/done cd ps; \ jadetex markup.tex; \ jadetex markup.tex; \ jadetex markup.tex ps/pxp.ps: ps/markup.dvi cd ps; \ dvips -f pxp.ps ps/pic/done: src/pic/*.fig mkdir -p ps/pic l=`cd src/pic; echo *.fig`; \ for x in $$l; do fig2dev -L ps -m 0.8 src/pic/$$x ps/pic/`basename $$x .fig`.ps; done touch ps/pic/done .SUFFIXES: .xml .sgml .sgml.xml: sx -xndata $< >$@; true pxp-1.2.9/doc/manual/index.txt0000644000175000017500000000257013055274551014663 0ustar gerdgerdPXP is an XML parser for O'Caml. It represents the parsed document either as tree or as stream of events. In tree mode, it is possible to validate the XML document against a DTD. The acronym PXP means Polymorphic XML Parser. This name reflects the ability to create XML trees with polymorphic type parameters. {2 Introduction} - {!Intro_getting_started}: Getting started, and a list of recipes - {!Intro_trees}: The structure of document trees - {!Intro_extensions}: Node extensions - {!Intro_events}: XML data as stream of events (also pull parsing) - {!Intro_namespaces}: Namespaces - {!Intro_resolution}: Resolving entity ID's - {!Intro_preprocessor}: The PXP preprocessor - {!Intro_advanced}: Advanced topics - {!Example_readme}: A code example explained: The [readme] processor {2 Reference} {!modules: Pxp_types Pxp_document Pxp_dtd Pxp_tree_parser Pxp_ev_parser Pxp_dtd_parser Pxp_event Pxp_codewriter Pxp_marshal Pxp_reader Pxp_core_types Pxp_yacc } {2 Index} {!indexlist} {2 Authors} PXP has been written by Gerd Stolpmann; it contains contributions by Claudio Sacerdoti Coen. You may copy it as you like, you may use it even for commercial purposes as long as the license conditions are respected, see the file LICENSE coming with the distribution. It allows almost everything. Thanks also to Alain Frisch and Haruo Hosoya for discussions and bug reports. pxp-1.2.9/doc/manual/style.css0000644000175000017500000000477113055274551014672 0ustar gerdgerda:visited {color : #416DFF; text-decoration : none; } a:link {color : #416DFF; text-decoration : none;} a:hover {color : Red; text-decoration : none; background-color: #5FFF88} a:active {color : Red; text-decoration : underline; } .keyword { font-weight : bold ; color : Red } .keywordsign { color : #C04600 } .superscript { font-size : 4 } .subscript { font-size : 4 } .comment { color : Green } .constructor { color : Blue } .type { color : #5C6585 } .string { color : Maroon } .warning { color : Red ; font-weight : bold } .info { margin-left : 1cm; margin-right : 2cm } .param_info { margin-top: 4px; margin-left : 1cm; margin-right : 2cm } .code { color : #465F91 ; } h1 { font-size : 20pt ; margin-top: 20pt; margin-bottom: 15t; text-align: center; padding: 5px; border: 1px solid #000000; } h2 { font-size : 20pt ; margin-top: 20pt; margin-bottom: 8pt; text-align: left; padding: 2px; margin-left: 1cm; border-bottom: 1px solid #777777; } h3 { font-size : 16pt ; margin-top: 20pt; margin-bottom: 8pt; text-align: left; padding: 2px; padding-left: 1cm; } h4 { font-size : 12pt ; margin-top: 12pt; margin-bottom: 6pt; text-align: left; padding: 2px; } h5 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90FDFF ;padding: 2px; } h6 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #C0FFFF ; padding: 2px; } div.h7 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #E0FFFF ; padding: 2px; } div.h8 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #F0FFFF ; padding: 2px; } div.h9 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #FFFFFF ; padding: 2px; } .typetable { border-style : hidden } .indextable { border-style : hidden } .paramstable { border-style : hidden ; padding: 5pt 5pt} body { background-color : White } td.typefieldcomment { font-size: smaller ;} pre { margin-bottom: 4px } div.sig_block {margin-left: 1cm} .picture { margin-left: 100px; } .picture-caption { font-weight: bold; padding-bottom: 10px; } .included-module-type { margin-left: 1cm; background-color: #EEE; } .included-module { margin-left: 1cm; background-color: #EEE; } pxp-1.2.9/doc/manual/html/0000755000175000017500000000000013055274552013754 5ustar gerdgerdpxp-1.2.9/doc/manual/html/ref/0000755000175000017500000000000013055274552014530 5ustar gerdgerdpxp-1.2.9/doc/manual/html/ref/style.css0000644000175000017500000000477113055274551016412 0ustar gerdgerda:visited {color : #416DFF; text-decoration : none; } a:link {color : #416DFF; text-decoration : none;} a:hover {color : Red; text-decoration : none; background-color: #5FFF88} a:active {color : Red; text-decoration : underline; } .keyword { font-weight : bold ; color : Red } .keywordsign { color : #C04600 } .superscript { font-size : 4 } .subscript { font-size : 4 } .comment { color : Green } .constructor { color : Blue } .type { color : #5C6585 } .string { color : Maroon } .warning { color : Red ; font-weight : bold } .info { margin-left : 1cm; margin-right : 2cm } .param_info { margin-top: 4px; margin-left : 1cm; margin-right : 2cm } .code { color : #465F91 ; } h1 { font-size : 20pt ; margin-top: 20pt; margin-bottom: 15t; text-align: center; padding: 5px; border: 1px solid #000000; } h2 { font-size : 20pt ; margin-top: 20pt; margin-bottom: 8pt; text-align: left; padding: 2px; margin-left: 1cm; border-bottom: 1px solid #777777; } h3 { font-size : 16pt ; margin-top: 20pt; margin-bottom: 8pt; text-align: left; padding: 2px; padding-left: 1cm; } h4 { font-size : 12pt ; margin-top: 12pt; margin-bottom: 6pt; text-align: left; padding: 2px; } h5 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90FDFF ;padding: 2px; } h6 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #C0FFFF ; padding: 2px; } div.h7 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #E0FFFF ; padding: 2px; } div.h8 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #F0FFFF ; padding: 2px; } div.h9 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #FFFFFF ; padding: 2px; } .typetable { border-style : hidden } .indextable { border-style : hidden } .paramstable { border-style : hidden ; padding: 5pt 5pt} body { background-color : White } td.typefieldcomment { font-size: smaller ;} pre { margin-bottom: 4px } div.sig_block {margin-left: 1cm} .picture { margin-left: 100px; } .picture-caption { font-weight: bold; padding-bottom: 10px; } .included-module-type { margin-left: 1cm; background-color: #EEE; } .included-module { margin-left: 1cm; background-color: #EEE; } pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.html0000644000175000017500000002202013055274551017013 0ustar gerdgerd PXP Reference : Pxp_dtd

Module Pxp_dtd

module Pxp_dtd: sig .. end
DTD objects

The DTD object is a separate container for the formal requirements of a document. The DTD object is always present in a document, even when validation is turned off. See Pxp_dtd.dtd for details about the DTD object.

There are a number of accompanying objects also defined in this module (e.g. namespace_manager or dtd_element).




class namespace_manager : object .. end
This class manages mappings from URIs to normalized prefixes.
val create_namespace_manager : unit -> namespace_manager
Preferred way of creating a namespace_manager
class type namespace_scope = object .. end
The recursive class type namespace_scope represents the original namespace declarations found in the XML text.
class namespace_scope_impl : namespace_manager -> namespace_scope option -> (string * string) list -> namespace_scope
An implementation of namespace_scope.
val create_namespace_scope : ?parent:namespace_scope ->
?decl:(string * string) list ->
namespace_manager -> namespace_scope
Preferred way of creating a namespace_scope
class dtd : ?swarner:Pxp_types.symbolic_warnings -> Pxp_types.collect_warnings -> Pxp_types.rep_encoding -> object .. end
DTD objects have two purposes: They are containers for global declarations that apply to the whole XML document. This includes the character set, the standalone declaration, and all declaration that can appear in the "DTD part" of a document., Also, they express formal constraints the document must fulfill such as validity, or (less ambitious) well-formedness. Normally, programmers neither need to create such objects, nor to fill them with data, as the parser already does this.
class dtd_element : dtd -> string -> object .. end
A single element declaration that can be added to the DTD object.
class dtd_notation : string -> Pxp_types.ext_id -> Pxp_types.rep_encoding -> object .. end
A single notation declaration that can be added to the DTD object.
class proc_instruction : string -> string -> Pxp_types.rep_encoding -> object .. end
A single processing instruction occuring in DTD scope.
val create_dtd : ?swarner:Pxp_types.symbolic_warnings ->
?warner:Pxp_types.collect_warnings ->
Pxp_types.rep_encoding -> dtd
Preferred way of creating a DTD. Example:
 let dtd = create_dtd 
             ?swarner:config.swarner
             ~warner:config.warner
             config.encoding

See also Pxp_dtd_parser.create_empty_dtd, which creates a DTD from a Pxp_types.config record.

module Entity: sig .. end
Useful properties of entities: The following submodule exports all stable properties of the entity classes.


pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.Entity.html0000644000175000017500000002110413055274551020270 0ustar gerdgerd PXP Reference : Pxp_dtd.Entity

Module Pxp_dtd.Entity

module Entity: sig .. end
Useful properties of entities: The following submodule exports all stable properties of the entity classes. Please use this module, and not Pxp_entity to access entities.

Note that the types entity and entity_id are also exported by Pxp_types.


val get_name : Pxp_entity.entity -> string
Return the name of the entity.
val get_full_name : Pxp_entity.entity -> string
The full name includes the ID, too (for diagnostics messages)
val get_encoding : Pxp_entity.entity -> Pxp_core_types.I.rep_encoding
Return the encoding of the internal representation of the entity
val get_type : Pxp_entity.entity -> [ `External | `Internal | `NDATA ]
Returns the type of the entity.
val replacement_text : Pxp_entity.entity -> string
Return the replacement text of the entity. Works for both internal and external entities. The replacement text is the "right side" of the entity definition.
val get_xid : Pxp_entity.entity -> Pxp_core_types.I.ext_id option
Returns the external ID for external and NDATA entities, and None for internal entities

TRAP: The external ID may be a relative SYSTEM ID, and it is not known to which base ID the relative ID must be resolved. So the external ID may be meaningless.

val get_resolver_id : Pxp_entity.entity -> Pxp_core_types.I.resolver_id option
Returns the resolver ID for external entities, and None for other entities. This is the version as returned by the active_id method by the resolver. The resolver ID contains more information than the external ID, for example the base URL relative to which SYSTEM IDs should be interpreted.
val get_notation : Pxp_entity.entity -> string option
Returns the notation of NDATA entities, and None for the other entity types
val create_internal_entity : name:string -> value:string -> Pxp_dtd.dtd -> Pxp_entity.entity
Creates an internal entity. The name and the value must be encoded in the same encoding as the DTD. Note that if the entity is to be used as parameter entity, the first and the last characters of the value should be spaces.
val create_ndata_entity : name:string ->
xid:Pxp_core_types.I.ext_id ->
notation:string -> Pxp_dtd.dtd -> Pxp_entity.entity
Creates an NDATA entity. The name and the notation must be encoded in the same encoding as the DTD. The external ID must be encoded as UTF-8 string (like all external IDs).
val create_external_entity : ?doc_entity:bool ->
?system_base:string ->
name:string ->
xid:Pxp_core_types.I.ext_id ->
resolver:Pxp_reader.resolver -> Pxp_dtd.dtd -> Pxp_entity.entity
Creates a reference to an external entity. The name must be encoded in the same encoding as the DTD. The external ID must be encoded as UTF-8 string (like all external IDs).

  • doc_entity: If true, the entity is a document entity. XML requires some additional restrictions for document entities. The default for the argument is false.
  • system_base: The base URL if SYSTEM identifiers are passed as xid

val from_external_source : ?doc_entity:bool ->
name:string -> Pxp_dtd.dtd -> Pxp_dtd.source -> Pxp_entity.entity
Creates an external entity that reads from the passed Pxp_types.source
val entity_id : Pxp_entity.entity -> Pxp_lexer_types.entity_id
Returns the abstract entity ID
val lookup : Pxp_lexer_types.entity_id -> Pxp_entity.entity
Looks the entity up for an entitiy ID
val create_entity_id : unit -> Pxp_lexer_types.entity_id
Create a new abstract entity ID. This ID can be used whereever an entity_id is expected but no entity is available, except that the back coercion lookup is not supported, and will raise Invalid_argument.
pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.Entity.html0000644000175000017500000001571213055274551021341 0ustar gerdgerd PXP Reference : Pxp_dtd.Entity sig
  val get_name : Pxp_entity.entity -> string
  val get_full_name : Pxp_entity.entity -> string
  val get_encoding : Pxp_entity.entity -> Pxp_core_types.I.rep_encoding
  val get_type : Pxp_entity.entity -> [ `External | `Internal | `NDATA ]
  val replacement_text : Pxp_entity.entity -> string
  val get_xid : Pxp_entity.entity -> Pxp_core_types.I.ext_id option
  val get_resolver_id :
    Pxp_entity.entity -> Pxp_core_types.I.resolver_id option
  val get_notation : Pxp_entity.entity -> string option
  val create_internal_entity :
    name:string -> value:string -> Pxp_dtd.dtd -> Pxp_entity.entity
  val create_ndata_entity :
    name:string ->
    xid:Pxp_core_types.I.ext_id ->
    notation:string -> Pxp_dtd.dtd -> Pxp_entity.entity
  val create_external_entity :
    ?doc_entity:bool ->
    ?system_base:string ->
    name:string ->
    xid:Pxp_core_types.I.ext_id ->
    resolver:Pxp_reader.resolver -> Pxp_dtd.dtd -> Pxp_entity.entity
  val from_external_source :
    ?doc_entity:bool ->
    name:string -> Pxp_dtd.dtd -> Pxp_dtd.source -> Pxp_entity.entity
  val entity_id : Pxp_entity.entity -> Pxp_lexer_types.entity_id
  val lookup : Pxp_lexer_types.entity_id -> Pxp_entity.entity
  val create_entity_id : unit -> Pxp_lexer_types.entity_id
end
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.namespace_manager-c.html0000644000175000017500000002377513055274551022702 0ustar gerdgerd PXP Reference : Pxp_dtd.namespace_manager

Class Pxp_dtd.namespace_manager

class namespace_manager : object .. end
This class manages mappings from URIs to normalized prefixes. For every namespace a namespace_manager object contains a set that maps various URI's to the same normalized prefix np:
 uri1 |-> np, uri2 |-> np, ..., uriN |-> np 
The normalized prefix np is characterstical of the namespace, and identifies the namespace uniquely. The first URI uri1 is the primary URI, the other URIs are aliases.

In order to create an empty namespace, call Pxp_dtd.create_namespace_manager.

See Intro_namespaces for an introduction to namespaces and more links to other explanations about namespace managers.

The following operations are supported:

  • add_namespace np uri: adds a new mapping uri |-> np to the manager. Neither np nor uri must already be part of another mapping in the manager.
  • add_uri np uri: adds a new alias uri for an existing namespace which is identified by the normprefix np. The normprefix np must already be part of a mapping which is then extended by this method.
  • lookup_or_add_namespace p uri: If there is already some mapping uri |-> np, the normprefix np is simply returned ("lookup"). In this case p is ignored. Otherwise uri is not yet mapped, and in this case some unique np must be found such that uri |-> np can be added (add_namespace). First, the passed prefix p is tried. If p is free, it can be taken as new normprefix: np = p. Otherwise some number n is found such that the concatenation p ^ n is free: np = p ^ n. The operation returns np.
Encodings: prefixes and URIs are always encoded in the default encoding of the document

method add_namespace : string -> string -> unit
add_namespace np uri: adds a new namespace to the object. The namespace is identified by the normprefix np and contains initially the primary URI uri. The method fails (Namespace_error) if either np already identifies some namespace or if uri is already member of some namespace. Nothing happens if uri is the sole member of the namespace np. It is required that np <> "".
method add_uri : string -> string -> unit
add_uri np uri: adds uri as alias URI to the namespace identified by the normprefix np (see above for detailed semantics). The method raises Namespace_prefix_not_managed if the normprefix np is unknown to the object, and it fails (Namespace_error) if the uri is member of a different namespace. Nothing happens if the uri is already member of the namespace np.

Change in PXP 1.2: Using exception Namespace_prefix_not_managed instead of Not_found.

method lookup_or_add_namespace : string -> string -> string
lookup_or_add_namespace p uri: first, the method looks up if the namespace for uri does already exist. If so, p is ignored, and the method returns the normprefix identifying the namespace. Otherwise, a new namespace is added for some normprefix np which initially contains uri. The normprefix np is calculated upon p serving as suggestion for the normprefix. The method returns the normprefix.
method get_primary_uri : string -> string
Return the primary URI for a normprefix, or raises Namespace_prefix_not_managed. get_uri "" raises always this exception.
method get_uri_list : string -> string list
Return all URIs for a normprefix, or [] if the normprefix is unused. get_uri_list "" returns always []. The last URI of the returned list is the primary URI.
method get_normprefix : string -> string
Return the normprefix for a URI, or raises Namespace_not_managed.
method iter_namespaces : (string -> unit) -> unit
Iterates over all namespaces contained in the object, and calls the passed function for every namespace. The argument of the invoked function is the normprefix of the namespace.
method as_declaration : (string * string) list
Returns the list of normprefixes and primary URIs. Useful to create the corresponding namespace scope, e.g.
new namespace_scope_impl mng None (mng#as_declaration) 

pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.namespace_manager.html0000644000175000017500000000661713055274551023517 0ustar gerdgerd PXP Reference : Pxp_dtd.namespace_manager object
  method add_namespace : string -> string -> unit
  method add_uri : string -> string -> unit
  method as_declaration : (string * string) list
  method get_normprefix : string -> string
  method get_primary_uri : string -> string
  method get_uri_list : string -> string list
  method iter_namespaces : (string -> unit) -> unit
  method lookup_or_add_namespace : string -> string -> string
end
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.namespace_scope_impl-c.html0000644000175000017500000000660513055274551023413 0ustar gerdgerd PXP Reference : Pxp_dtd.namespace_scope_impl

Class Pxp_dtd.namespace_scope_impl

class namespace_scope_impl : namespace_manager -> namespace_scope option -> (string * string) list -> namespace_scope
An implementation of namespace_scope. New scopes are created by
 new namespace_scope_impl mng parent_opt decl 
where mng is the namespace managaer, parent_opt is the optional parent scope, and decl is the declaration list.

pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.namespace_scope_impl.html0000644000175000017500000000452513055274551024233 0ustar gerdgerd PXP Reference : Pxp_dtd.namespace_scope_impl Pxp_dtd.namespace_manager ->
Pxp_dtd.namespace_scope option ->
(string * string) list -> Pxp_dtd.namespace_scope
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.dtd-c.html0000644000175000017500000004624613055274551020025 0ustar gerdgerd PXP Reference : Pxp_dtd.dtd

Class Pxp_dtd.dtd

class dtd : ?swarner:Pxp_core_types.I.symbolic_warnings -> Pxp_core_types.I.collect_warnings -> Pxp_core_types.I.rep_encoding -> object .. end
DTD objects have two purposes:
  • They are containers for global declarations that apply to the whole XML document. This includes the character set, the standalone declaration, and all declaration that can appear in the "DTD part" of a document.
  • Also, they express formal constraints the document must fulfill such as validity, or (less ambitious) well-formedness.
Normally, programmers neither need to create such objects, nor to fill them with data, as the parser already does this. If it is required to create a DTD object, the recommended function is Pxp_dtd.create_dtd.

Despite its name, this object does not only define the DTD as such (i.e. what would be found in a ".dtd" file), but all formal requirements of documents that are needed by PXP. This also includes:

  • The name of the root element
  • The character encoding of the document
  • Whether validation is on or off
  • The namespace manager
  • Whether the document is declared as standalone
A consequence of this is that even documents have a DTD object that only have to comply to the relatively weak well-formedness constraints.

For some introductory words about well-formedness mode, see Parsing in well-formedness mode.


method root : string option
get the name of the root element if present. This is the name following "<!DOCTYPE". If there is no DOCTYPE declaration, this method will return None.
method set_root : string -> unit
set the name of the root element. This method can be invoked only once (usually by the parser)
method id : Pxp_core_types.I.dtd_id option
get the identifier for this DTD. Possible return values:
  • None: There is no DOCTYPE declaration, or only <!DOCTYPE name>
  • Some Internal: There is a DOCTYPE declaration with material in brackets like <!DOCTYPE name [ declarations ... ]>
  • Some(External xid): There is a DOCTYPE declaration with a SYSTEM or PUBLIC identifier (described by xid), but without brackets, i.e. <!DOCTYPE name SYSTEM '...'> or <!DOCTYPE name PUBLIC '...' '...'> .
  • Some(Derived xid): There is a DOCTYPE declaration with a SYSTEM or PUBLIC identifier (described by xid), and with brackets

method set_id : Pxp_core_types.I.dtd_id -> unit
set the identifier. This method can be invoked only once
method encoding : Pxp_core_types.I.rep_encoding
returns the encoding used for character representation
method lexer_factory : Pxp_lexer_types.lexer_factory
Returns a lexer factory for the character encoding
method allow_arbitrary : unit
This method sets the arbitrary_allowed flag. This flag disables a specific validation constraint, namely that all elements need to be declared in the DTD. This feature is used to implement the well-formedness mode: In this mode, the element, attribute, and notation declarations found in the textual DTD are ignored, and not added to this DTD object. As the arbitrary_allowed flag is also set, the net effect is that all validation checks regarding the values of elements and attributes are omitted. The flag is automatically set if the parser is called using one of the "wf" functions, e.g. Pxp_tree_parser.parse_wfdocument_entity.

Technically, the arbitrary_allowed flag changes the behaviour of the element and notation methods defined below so that they raise Undeclared instead of Validation_error when an unknown element or notation name is encountered.

method disallow_arbitrary : unit
Clears the arbitrary_allowed flag again
method arbitrary_allowed : bool
Returns whether arbitrary contents are allowed or not.
method standalone_declaration : bool
Whether there is a 'standalone' declaration or not.
method set_standalone_declaration : bool -> unit
Sets the 'standalone' declaration.
method namespace_manager : namespace_manager
For namespace-aware implementations of the node class, this method returns the namespace manager. If the namespace manager has not been set, the exception Not_found is raised.
method set_namespace_manager : namespace_manager -> unit
Sets the namespace manager as returned by namespace_manager.
method add_element : dtd_element -> unit
add the given element declaration to this DTD. Raises Not_found if there is already an element declaration with the same name.
method add_gen_entity : Pxp_entity.entity -> bool -> unit
add_gen_entity e extdecl: add the entity e as general entity to this DTD (general entities are those represented by &name;). If there is already a declaration with the same name, the second definition is ignored; as exception from this rule, entities with names "lt", "gt", "amp", "quot", and "apos" may only be redeclared with a definition that is equivalent to the standard definition; otherwise a Validation_error is raised.

extdecl: true indicates that the entity declaration occurs in an external entity. (Used for the standalone check.)

method add_par_entity : Pxp_entity.entity -> unit
add the given entity as parameter entity to this DTD (parameter entities are those represented by %name;). If there is already a declaration with the same name, the second definition is ignored.
method add_notation : dtd_notation -> unit
add the given notation to this DTD. If there is already a declaration with the same name, a Validation_error is raised.
method add_pinstr : proc_instruction -> unit
add the given processing instruction to this DTD.
method element : string -> dtd_element
looks up the element declaration with the given name. Raises Validation_error if the element cannot be found. If the arbitrary_allowed flag is set, however, Undeclared is raised instead.
method element_names : string list
returns the list of the names of all element declarations.
method gen_entity : string -> Pxp_entity.entity * bool
let e, extdecl = obj # gen_entity n: looks up the general entity e with the name n. Raises WF_error if the entity cannot be found.

extdecl: indicates whether the entity declaration occured in an external entity.

method gen_entity_names : string list
returns the list of all general entity names
method par_entity : string -> Pxp_entity.entity
looks up the parameter entity with the given name. Raises WF_error if the entity cannot be found.
method par_entity_names : string list
returns the list of all parameter entity names
method notation : string -> dtd_notation
looks up the notation declaration with the given name. Raises Validation_error if the notation cannot be found. If the arbitrary_allowed flag is sez, however, Undeclared is raised instead.
method notation_names : string list
Returns the list of the names of all added notations
method pinstr : string -> proc_instruction list
looks up all processing instructions with the given target. The "target" is the identifier following <?.
method pinstr_names : string list
Returns the list of the names (targets) of all added pinstrs
method validate : unit
ensures that the DTD is valid. This method is optimized such that actual validation is only performed if DTD has been changed. If the DTD is invalid, in most cases a Validation_error is raised, but other exceptions are possible, too.
method only_deterministic_models : unit
Succeeds if all regexp content models are deterministic. Otherwise Validation_error.
method write : ?root:string ->
Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> bool -> unit
write os enc doctype: Writes the DTD as enc-encoded string to os. If doctype, a DTD like <!DOCTYPE root [ ... ]> is written. If not doctype, only the declarations are written (the material within the square brackets).

The entity definitions are not written. However, it is ensured that the generated string does not contain any reference to an entity. The reason for the omission of the entites is that there is no generic way of writing references to external entities.

Option root: Override the name of the root element in the DOCTYPE clause.

method write_ref : ?root:string ->
Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
write_ref os enc: Writes a reference to the DTD as enc-encoded string to os. The reference looks as follows:
   <!DOCTYPE root SYSTEM ... > or
   <!DOCTYPE root PUBLIC ... >
 
Of course, the DTD must have an external ID:
  • dtd#id = External(System ...) or
  • dtd#id = External(Public ...)
If the DTD is internal or mixed, the method write_ref will fail. If the ID is anonymous or private, the method will fail, too.

Option root: Override the name of the root element in the DOCTYPE clause.

pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.dtd.html0000644000175000017500000002045013055274551020633 0ustar gerdgerd PXP Reference : Pxp_dtd.dtd ?swarner:Pxp_core_types.I.symbolic_warnings ->
Pxp_core_types.I.collect_warnings ->
Pxp_core_types.I.rep_encoding ->
object
  method add_element : Pxp_dtd.dtd_element -> unit
  method add_gen_entity : Pxp_entity.entity -> bool -> unit
  method add_notation : Pxp_dtd.dtd_notation -> unit
  method add_par_entity : Pxp_entity.entity -> unit
  method add_pinstr : Pxp_dtd.proc_instruction -> unit
  method allow_arbitrary : unit
  method arbitrary_allowed : bool
  method disallow_arbitrary : unit
  method element : string -> Pxp_dtd.dtd_element
  method element_names : string list
  method encoding : Pxp_core_types.I.rep_encoding
  method gen_entity : string -> Pxp_entity.entity * bool
  method gen_entity_names : string list
  method id : Pxp_core_types.I.dtd_id option
  method invalidate : unit
  method lexer_factory : Pxp_lexer_types.lexer_factory
  method namespace_manager : Pxp_dtd.namespace_manager
  method notation : string -> Pxp_dtd.dtd_notation
  method notation_names : string list
  method only_deterministic_models : unit
  method par_entity : string -> Pxp_entity.entity
  method par_entity_names : string list
  method pinstr : string -> Pxp_dtd.proc_instruction list
  method pinstr_names : string list
  method root : string option
  method set_id : Pxp_core_types.I.dtd_id -> unit
  method set_namespace_manager : Pxp_dtd.namespace_manager -> unit
  method set_root : string -> unit
  method set_standalone_declaration : bool -> unit
  method standalone_declaration : bool
  method swarner : Pxp_core_types.I.symbolic_warnings option
  method validate : unit
  method warner : Pxp_core_types.I.collect_warnings
  method write :
    ?root:string ->
    Pxp_core_types.I.output_stream ->
    Pxp_core_types.I.encoding -> bool -> unit
  method write_ref :
    ?root:string ->
    Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
end
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.dtd_element-c.html0000644000175000017500000002546313055274551021534 0ustar gerdgerd PXP Reference : Pxp_dtd.dtd_element

Class Pxp_dtd.dtd_element

class dtd_element : dtd -> string -> object .. end
A single element declaration that can be added to the DTD object. Element declarations are created by
 new dtd_element init_dtd init_name 
This creates a new dtd_element object for init_dtd with init_name. The strings are represented in the same encoding as init_dtd.

method name : string
returns the name of the declared element
method externally_declared : bool
returns whether the element declaration occurs in an external entity.
method content_model : Pxp_core_types.I.content_model_type
get the content model of this element declaration, or Unspecified
method content_dfa : Pxp_dfa.dfa_definition option
return the DFA of the content model if there is a DFA, or None. A DFA exists only for regexp style content models which are deterministic.
method set_cm_and_extdecl : Pxp_core_types.I.content_model_type -> bool -> unit
set_cm_and_extdecl cm extdecl: set the content model to cm. Once the content model is not Unspecified, it cannot be set to a different value again. Furthermore, it is set whether the element occurs in an external entity (extdecl).
method encoding : Pxp_core_types.I.rep_encoding
Return the encoding of the strings
method allow_arbitrary : unit
This method sets the arbitrary_allowed flag for this element. The effect of this flag is to ignore the validation constraint that attributes for this element needs to be declared. Note that this mode is not required for implementing the well-formedness mode, because for this it is already sufficient to set the same-named flag in the global DTD object. Setting this flag for certain elements may still be useful, however. It is then possible to allow arbitrary attributes for certain elements only.

Technically, the arbitrary_allowed flag changes the behaviour of the attribute method defined below so that it raises Undeclared instead of Validation_error when an unknown attribute name is encountered.

method disallow_arbitrary : unit
Clears the arbitrary_allowed flag
method arbitrary_allowed : bool
Returns whether arbitrary attributes are allowed or not.
method attribute : string -> Pxp_core_types.I.att_type * Pxp_core_types.I.att_default
get the type and default value of a declared attribute, or raise Validation_error if the attribute does not exist. If the arbitrary_allowed flag is set, the exception Undeclared is raised instead of Validation_error.
method attribute_violates_standalone_declaration : string -> string option -> bool
attribute_violates_standalone_declaration name v: Checks whether the attribute name violates the standalone declaration if it has value v. The method returns true if:
  • The attribute declaration occurs in an external entity,
and if one of the two conditions holds:
  • v = None, and there is a default for the attribute value
  • v = Some s, and the type of the attribute is not CDATA, and s changes if normalized according to the rules of the attribute type.
The method raises Validation_error if the attribute does not exist. If the arbitrary_allowed flag is set, the exception Undeclared is raised instead of Validation_error.
method attribute_names : string list
get the list of all declared attributes
method names_of_required_attributes : string list
get the list of all attributes that are specified as required attributes
method id_attribute_name : string option
Returns the name of the attribute with type ID, or None.
method idref_attribute_names : string list
Returns the names of the attributes with type IDREF or IDREFS.
method add_attribute : string ->
Pxp_core_types.I.att_type -> Pxp_core_types.I.att_default -> bool -> unit
add_attribute name type default extdecl: add an attribute declaration for an attribute with the given name, type, and default value. If there is more than one declaration for an attribute name, the first declaration counts; the other declarations are ignored.

extdecl: if true, the attribute declaration occurs in an external entity. This property is used to check the "standalone" attribute.

method validate : unit
checks whether this element declaration (i.e. the content model and all attribute declarations) is valid for the associated DTD. Raises mostly Validation_error if the validation fails.
pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.dtd_element.html0000644000175000017500000001311113055274551022340 0ustar gerdgerd PXP Reference : Pxp_dtd.dtd_element Pxp_dtd.dtd ->
string ->
object
  method add_attribute :
    string ->
    Pxp_core_types.I.att_type -> Pxp_core_types.I.att_default -> bool -> unit
  method allow_arbitrary : unit
  method arbitrary_allowed : bool
  method attribute :
    string -> Pxp_core_types.I.att_type * Pxp_core_types.I.att_default
  method attribute_names : string list
  method attribute_violates_standalone_declaration :
    string -> string option -> bool
  method content_dfa : Pxp_dfa.dfa_definition option
  method content_model : Pxp_core_types.I.content_model_type
  method disallow_arbitrary : unit
  method encoding : Pxp_core_types.I.rep_encoding
  method externally_declared : bool
  method id_attribute_name : string option
  method idref_attribute_names : string list
  method internal_vr : Pxp_dtd.validation_record
  method name : string
  method names_of_required_attributes : string list
  method set_cm_and_extdecl :
    Pxp_core_types.I.content_model_type -> bool -> unit
  method validate : unit
  method write :
    Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
end
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.dtd_notation-c.html0000644000175000017500000000724213055274551021731 0ustar gerdgerd PXP Reference : Pxp_dtd.dtd_notation

Class Pxp_dtd.dtd_notation

class dtd_notation : string -> Pxp_core_types.I.ext_id -> Pxp_core_types.I.rep_encoding -> object .. end
A single notation declaration that can be added to the DTD object. Notation declarations are created by
 new dtd_notation a_name an_external_ID init_encoding 
This creates a new dtd_notation object with the given name and the given external ID.

method name : string
method ext_id : Pxp_core_types.I.ext_id
method encoding : Pxp_core_types.I.rep_encoding
pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.dtd_notation.html0000644000175000017500000000624213055274551022551 0ustar gerdgerd PXP Reference : Pxp_dtd.dtd_notation string ->
Pxp_core_types.I.ext_id ->
Pxp_core_types.I.rep_encoding ->
object
  method encoding : Pxp_core_types.I.rep_encoding
  method ext_id : Pxp_core_types.I.ext_id
  method name : string
  method write :
    Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
end
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.proc_instruction-c.html0000644000175000017500000001060613055274551022645 0ustar gerdgerd PXP Reference : Pxp_dtd.proc_instruction

Class Pxp_dtd.proc_instruction

class proc_instruction : string -> string -> Pxp_core_types.I.rep_encoding -> object .. end
A single processing instruction occuring in DTD scope. This instruction can also be added to the DTD object, Creation:
 new proc_instruction a_target a_value 
creates a new proc_instruction object with the given target string and the given value string. Note: A processing instruction is written as <?target value?> .

method target : string
method value : string
method encoding : Pxp_core_types.I.rep_encoding
method parse_pxp_option : string * string * (string * string) list
Parses a PI containing a PXP option. Such PIs are formed like:
 <?target option-name option-att="value" option-att="value" ... ?> 
The method returns a triple
 (target, option-name, [option-att, value; ...]) 
or raises Error.
pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.proc_instruction.html0000644000175000017500000000624313055274551023470 0ustar gerdgerd PXP Reference : Pxp_dtd.proc_instruction string ->
string ->
Pxp_core_types.I.rep_encoding ->
object
  method encoding : Pxp_core_types.I.rep_encoding
  method parse_pxp_option : string * string * (string * string) list
  method target : string
  method value : string
  method write :
    Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
end
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd.namespace_scope-c.html0000644000175000017500000002037013055274551022365 0ustar gerdgerd PXP Reference : Pxp_dtd.namespace_scope

Class type Pxp_dtd.namespace_scope

class type namespace_scope = object .. end
The recursive class type namespace_scope represents the original namespace declarations found in the XML text. A single namespace_scope object contains a list of declared namespaces
 [ (dp1, uri1); (dp2; uri2); ... ] 
corresponding to the "xmlns"-type declarations found in a single XML element:
 <element xmlns:dp1="uri1" xmlns:dp2="uri2" ... > 
For the declaration of a default namespace xmlns="uri" the pair ("",uri) must be included in the list. The special pair ("","") means that the former default namespace is "undeclared".

Furthermore, the namespace_scope object may have a parent namespace_scope, representing the namespace declarations in the surrounding XML text. namespace_scope objects are intentionally immutable. When some XML subtree is cut out of a document and inserted into another document, the original namespace_scope declarations (including all parents) are still applied to the subtree when it is in the new document. Further changes in the old document cannot break this assertion because of the immutability.

The namespace_scope objects are connected with the namespace_manager to allow translations from the namespace prefixes found in the XML text (also called "display prefixes" from now on) to the normalized prefixes stored in the namespace_manager, and vice versa.

Call Pxp_dtd.create_namespace_scope to create a scope object using the default implementation.

See Intro_namespaces for an introduction to namespaces and more links to other explanations about scopes.


method namespace_manager : namespace_manager
Returns the namespace_manager to which this scope object is connected
method parent_scope : namespace_scope option
Returns the parent object, if any
method declaration : (string * string) list
Returns the list of namespace declarations of this scope (i.e. the declarations in parent objects are not considered). The list contains pairs (display_prefix, uri) .
method effective_declaration : (string * string) list
Returns the list of namespace declarations of this scope and all parent scopes. The list contains pairs (display_prefix, uri) . Prefixes hidden by earlier declarations are suppressed in the list
method display_prefix_of_uri : string -> string
Translates the URI to the corresponding display prefix as declared in this object or any parent object. Raises Namespace_not_in_scope when the declaration cannot be found.
method display_prefix_of_normprefix : string -> string
Translates the normalized prefix to the corresponding display prefix as declared in this object or any parent object. Raises Namespace_not_in_scope when the declaration cannot be found, and Namespace_prefix_not_managed when the normalized prefix is unknown to the namespace manager.
method uri_of_display_prefix : string -> string
Translates the display prefix to the corresponding URI as declared in this object or any parent object. Raises Not_found when the declaration cannot be found.
method normprefix_of_display_prefix : string -> string
Translates the display prefix to the corresponding normalized prefix as declared in this object or any parent object. Raises Not_found when the declaration cannot be found, and Namespace_not_managed when the namespace manager does not know the namespace.
pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.namespace_scope.html0000644000175000017500000000630013055274551023203 0ustar gerdgerd PXP Reference : Pxp_dtd.namespace_scope object
  method declaration : (string * string) list
  method display_prefix_of_normprefix : string -> string
  method display_prefix_of_uri : string -> string
  method effective_declaration : (string * string) list
  method namespace_manager : Pxp_dtd.namespace_manager
  method normprefix_of_display_prefix : string -> string
  method parent_scope : Pxp_dtd.namespace_scope option
  method uri_of_display_prefix : string -> string
end
pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd.html0000644000175000017500000007412113055274551020065 0ustar gerdgerd PXP Reference : Pxp_dtd sig
  type validation_record = {
    content_model : Pxp_core_types.I.content_model_type;
    content_dfa : Pxp_dfa.dfa_definition option Lazy.t;
    id_att_name : string option;
    idref_att_names : string list;
    att_lookup : int Pxp_aux.Str_hashtbl.t;
    init_att_vals : (string * Pxp_core_types.I.att_value) array;
    att_info : (Pxp_core_types.I.att_type * bool) array;
    att_required : int list;
    accept_undeclared_atts : bool;
  }
  class namespace_manager :
    object
      method add_namespace : string -> string -> unit
      method add_uri : string -> string -> unit
      method as_declaration : (string * string) list
      method get_normprefix : string -> string
      method get_primary_uri : string -> string
      method get_uri_list : string -> string list
      method iter_namespaces : (string -> unit) -> unit
      method lookup_or_add_namespace : string -> string -> string
    end
  val create_namespace_manager : unit -> Pxp_dtd.namespace_manager
  class type namespace_scope =
    object
      method declaration : (string * string) list
      method display_prefix_of_normprefix : string -> string
      method display_prefix_of_uri : string -> string
      method effective_declaration : (string * string) list
      method namespace_manager : Pxp_dtd.namespace_manager
      method normprefix_of_display_prefix : string -> string
      method parent_scope : Pxp_dtd.namespace_scope option
      method uri_of_display_prefix : string -> string
    end
  class namespace_scope_impl :
    Pxp_dtd.namespace_manager ->
    Pxp_dtd.namespace_scope option ->
    (string * string) list -> namespace_scope
  val create_namespace_scope :
    ?parent:Pxp_dtd.namespace_scope ->
    ?decl:(string * string) list ->
    Pxp_dtd.namespace_manager -> Pxp_dtd.namespace_scope
  class dtd :
    ?swarner:Pxp_core_types.I.symbolic_warnings ->
    Pxp_core_types.I.collect_warnings ->
    Pxp_core_types.I.rep_encoding ->
    object
      method add_element : Pxp_dtd.dtd_element -> unit
      method add_gen_entity : Pxp_entity.entity -> bool -> unit
      method add_notation : Pxp_dtd.dtd_notation -> unit
      method add_par_entity : Pxp_entity.entity -> unit
      method add_pinstr : Pxp_dtd.proc_instruction -> unit
      method allow_arbitrary : unit
      method arbitrary_allowed : bool
      method disallow_arbitrary : unit
      method element : string -> Pxp_dtd.dtd_element
      method element_names : string list
      method encoding : Pxp_core_types.I.rep_encoding
      method gen_entity : string -> Pxp_entity.entity * bool
      method gen_entity_names : string list
      method id : Pxp_core_types.I.dtd_id option
      method invalidate : unit
      method lexer_factory : Pxp_lexer_types.lexer_factory
      method namespace_manager : Pxp_dtd.namespace_manager
      method notation : string -> Pxp_dtd.dtd_notation
      method notation_names : string list
      method only_deterministic_models : unit
      method par_entity : string -> Pxp_entity.entity
      method par_entity_names : string list
      method pinstr : string -> Pxp_dtd.proc_instruction list
      method pinstr_names : string list
      method root : string option
      method set_id : Pxp_core_types.I.dtd_id -> unit
      method set_namespace_manager : Pxp_dtd.namespace_manager -> unit
      method set_root : string -> unit
      method set_standalone_declaration : bool -> unit
      method standalone_declaration : bool
      method swarner : Pxp_core_types.I.symbolic_warnings option
      method validate : unit
      method warner : Pxp_core_types.I.collect_warnings
      method write :
        ?root:string ->
        Pxp_core_types.I.output_stream ->
        Pxp_core_types.I.encoding -> bool -> unit
      method write_ref :
        ?root:string ->
        Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
    end
  and dtd_element :
    Pxp_dtd.dtd ->
    string ->
    object
      method add_attribute :
        string ->
        Pxp_core_types.I.att_type ->
        Pxp_core_types.I.att_default -> bool -> unit
      method allow_arbitrary : unit
      method arbitrary_allowed : bool
      method attribute :
        string -> Pxp_core_types.I.att_type * Pxp_core_types.I.att_default
      method attribute_names : string list
      method attribute_violates_standalone_declaration :
        string -> string option -> bool
      method content_dfa : Pxp_dfa.dfa_definition option
      method content_model : Pxp_core_types.I.content_model_type
      method disallow_arbitrary : unit
      method encoding : Pxp_core_types.I.rep_encoding
      method externally_declared : bool
      method id_attribute_name : string option
      method idref_attribute_names : string list
      method internal_vr : Pxp_dtd.validation_record
      method name : string
      method names_of_required_attributes : string list
      method set_cm_and_extdecl :
        Pxp_core_types.I.content_model_type -> bool -> unit
      method validate : unit
      method write :
        Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
    end
  and dtd_notation :
    string ->
    Pxp_core_types.I.ext_id ->
    Pxp_core_types.I.rep_encoding ->
    object
      method encoding : Pxp_core_types.I.rep_encoding
      method ext_id : Pxp_core_types.I.ext_id
      method name : string
      method write :
        Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
    end
  and proc_instruction :
    string ->
    string ->
    Pxp_core_types.I.rep_encoding ->
    object
      method encoding : Pxp_core_types.I.rep_encoding
      method parse_pxp_option : string * string * (string * string) list
      method target : string
      method value : string
      method write :
        Pxp_core_types.I.output_stream -> Pxp_core_types.I.encoding -> unit
    end
  val create_dtd :
    ?swarner:Pxp_core_types.I.symbolic_warnings ->
    ?warner:Pxp_core_types.I.collect_warnings ->
    Pxp_core_types.I.rep_encoding -> Pxp_dtd.dtd
  type source =
      Entity of ((Pxp_dtd.dtd -> Pxp_entity.entity) * Pxp_reader.resolver)
    | ExtID of (Pxp_core_types.I.ext_id * Pxp_reader.resolver)
    | XExtID of
        (Pxp_core_types.I.ext_id * string option * Pxp_reader.resolver)
  module Entity :
    sig
      val get_name : Pxp_entity.entity -> string
      val get_full_name : Pxp_entity.entity -> string
      val get_encoding : Pxp_entity.entity -> Pxp_core_types.I.rep_encoding
      val get_type : Pxp_entity.entity -> [ `External | `Internal | `NDATA ]
      val replacement_text : Pxp_entity.entity -> string
      val get_xid : Pxp_entity.entity -> Pxp_core_types.I.ext_id option
      val get_resolver_id :
        Pxp_entity.entity -> Pxp_core_types.I.resolver_id option
      val get_notation : Pxp_entity.entity -> string option
      val create_internal_entity :
        name:string -> value:string -> Pxp_dtd.dtd -> Pxp_entity.entity
      val create_ndata_entity :
        name:string ->
        xid:Pxp_core_types.I.ext_id ->
        notation:string -> Pxp_dtd.dtd -> Pxp_entity.entity
      val create_external_entity :
        ?doc_entity:bool ->
        ?system_base:string ->
        name:string ->
        xid:Pxp_core_types.I.ext_id ->
        resolver:Pxp_reader.resolver -> Pxp_dtd.dtd -> Pxp_entity.entity
      val from_external_source :
        ?doc_entity:bool ->
        name:string -> Pxp_dtd.dtd -> Pxp_dtd.source -> Pxp_entity.entity
      val entity_id : Pxp_entity.entity -> Pxp_lexer_types.entity_id
      val lookup : Pxp_lexer_types.entity_id -> Pxp_entity.entity
      val create_entity_id : unit -> Pxp_lexer_types.entity_id
    end
end
pxp-1.2.9/doc/manual/html/ref/Pxp_tree_parser.html0000644000175000017500000003660713055274551020573 0ustar gerdgerd PXP Reference : Pxp_tree_parser

Module Pxp_tree_parser

module Pxp_tree_parser: sig .. end
Calling the parser in tree mode


The following functions return the parsed XML text as tree, i.e. as Pxp_document.node or Pxp_document.document.

ID indices



These indices are used to check the uniqueness of elements declared as ID. Of course, the indices can also be used to quickly look up such elements.
exception ID_not_unique
Used inside Pxp_tree_parser.index to indicate that the same ID is attached to several nodes
class type [< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a]
index
= object .. end
The type of indexes over the ID attributes of the elements.
class [< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a]
hash_index
: object .. end
This is a simple implementation of Pxp_tree_parser.index using a hash table.

Parsing functions



There are two types of XML texts one can parse:
  • Closed XML documents
  • External XML entities
Usually, the functions for closed XML documents are the right ones. The exact difference between both types is subtle, as many texts are parseable in both ways. The idea, however, is that an external XML entity is text from a different file that is included by reference into a closed document. Some XML features are only meaningful for the whole document, and are not available when only an external entity is parsed. This includes:
  • The DOCTYPE and the DTD declarations
  • The standalone declaration
It is a syntax error to use these features in an external XML entity.

An external entity is a file referenced by another XML text. For example, this document includes "file.xml" as external entity:

       <?xml version="1.0"?>
       <!DOCTYPE root [
          <!ENTITY extref SYSTEM "file.xml">
       ]>
       <root>
         &extref;
       </root>
     

(In contrast to this, an internal entity would give the definition text immediately, e.g. <!ENTITY intref "This is the entity text">.) Of course, it does not make sense that the external entity has another DOCTYPE definition, and hence it is forbidden to use this feature in "file.xml".

There is no function to exactly parse a file like "file.xml" as if it was included into a bigger document. The closest behavior show Pxp_tree_parser.parse_content_entity and Pxp_tree_parser.parse_wfcontent_entity. They implement the additional constraint that the file has to have a single top-most element.

The following functions also distinguish between validating and well-formedness mode. In the latter mode, many formal document constraints are not enforced. For instance, elements and attributes need not to be declared.

There are, unfortunately, a number of myths about well-formed XML documents. One says that the declarations are completely ignored. This is of course not true. For example, the above shown example includes the external XML entity "file.xml" by reference. The <!ENTITY> declaration is respected no matter in which mode the parser is run. Also, it is not true that the presence of DOCTYPE indicates validated mode and the absence well-formedness mode. The presence of DOCTYPE is perfectly compatible with well-formedness mode - only that the declarations are interpreted in a different way.

If it is tried to parse a document in validating mode, but the DOCTYPE is missing, this parser will fail when the root element is parsed, because its declaration is missing. This conforms to the XML standard, and also follows the logic that the program calling the parser is written in the expectation that the parsed file is validated. If this validation is missing, the program can run into failed assertions (or worse).

val parse_document_entity : ?transform_dtd:(Pxp_dtd.dtd -> Pxp_dtd.dtd) ->
?id_index:(< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a)
index ->
Pxp_types.config ->
Pxp_types.source -> 'a Pxp_document.spec -> 'a Pxp_document.document
Parse a closed document, and validate the contents of the document against the DTD contained and/or referenced in the document.

If the optional argument transform_dtd is passed, the following modification applies: After the DTD (both the internal and external subsets) has been read, the function transform_dtd is called, and the resulting DTD is actually used to validate the document. This makes it possible

  • to check which DTD is used (e.g. by comparing Pxp_dtd.dtd.id with a list of allowed ID's)
  • to apply modifications to the DTD before content parsing is started
  • to even switch to a built-in DTD, and to drop all user-defined declarations.
If the optional argument transform_dtd is missing, the parser behaves in the same way as if the identity were passed as transform_dtd, i.e. the DTD is left unmodified.

If the optional argument id_index is present, the parser adds any ID attribute to the passed index. An index is required to detect violations of the uniqueness of IDs.

val parse_wfdocument_entity : ?transform_dtd:(Pxp_dtd.dtd -> Pxp_dtd.dtd) ->
Pxp_types.config ->
Pxp_types.source ->
(< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a)
Pxp_document.spec -> 'a Pxp_document.document
Parse a closed document, but do not validate it. Only checks on well-formedness are performed.

The option transform_dtd works as for parse_document_entity, but the resulting DTD is not used for validation. It is just included into the returned document (e.g. useful to get entity declarations).

val parse_content_entity : ?id_index:(< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a)
index ->
Pxp_types.config ->
Pxp_types.source ->
Pxp_dtd.dtd -> 'a Pxp_document.spec -> 'a Pxp_document.node
Parse a file representing a well-formed fragment of a document. The fragment must be a single element (i.e. something like <a>...</a>; not a sequence like <a>...</a><b>...</b>). The element is validated against the passed DTD, but it is not checked whether the element is the root element specified in the DTD. This function is almost always the wrong one to call. Rather consider Pxp_tree_parser.parse_document_entity.

Despite its name, this function cannot parse the content production defined in the XML specification! This is a misnomer I'm sorry about. The content production would allow to parse a list of elements and other node kinds. Also, this function corresponds to the event entry point `Entry_element_content and not `Entry_content.

If the optional argument id_index is present, the parser adds any ID attribute to the passed index. An index is required to detect violations of the uniqueness of IDs.

val parse_wfcontent_entity : Pxp_types.config ->
Pxp_types.source ->
(< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a)
Pxp_document.spec -> 'a Pxp_document.node
Parse a file representing a well-formed fragment of a document. The fragment is not validated, only checked for well-formedness. See also the notes for Pxp_tree_parser.parse_content_entity.

Helpers


val default_extension : 'a Pxp_document.node Pxp_document.extension as 'a
A "null" extension; an extension that does not extend the functionality
val default_spec : ('a Pxp_document.node Pxp_document.extension as 'a) Pxp_document.spec
Specifies that you do not want to use extensions.
val default_namespace_spec : ('a Pxp_document.node Pxp_document.extension as 'a) Pxp_document.spec
Specifies that you want to use namespace, but not extensions
pxp-1.2.9/doc/manual/html/ref/Pxp_tree_parser.hash_index-c.html0000644000175000017500000000760713055274551023122 0ustar gerdgerd PXP Reference : Pxp_tree_parser.hash_index

Class Pxp_tree_parser.hash_index

class [< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a]
hash_index
: object .. end
This is a simple implementation of Pxp_tree_parser.index using a hash table.

method add : string -> 'a Pxp_document.node -> unit
Add the passed node to the index. If there is already an ID with the passed string value, the exception Pxp_tree_parser.ID_not_unique is raised.
method find : string -> 'a Pxp_document.node
Finds the node with the passed ID value, or raises Not_found
method index : (string, 'a Pxp_document.node) Hashtbl.t
Returns the hash table mapping IDs to nodes.
pxp-1.2.9/doc/manual/html/ref/type_Pxp_tree_parser.hash_index.html0000644000175000017500000000645513055274551023743 0ustar gerdgerd PXP Reference : Pxp_tree_parser.hash_index object
  method add :
    string ->
    (< clone : 'a; node : 'Pxp_document.node;
       set_node : 'Pxp_document.node -> unit; .. >
     as 'a)
    Pxp_document.node -> unit
  method find : string -> 'Pxp_document.node
  method index : (string, 'Pxp_document.node) Hashtbl.t
end
pxp-1.2.9/doc/manual/html/ref/Pxp_tree_parser.index-c.html0000644000175000017500000000732213055274551022111 0ustar gerdgerd PXP Reference : Pxp_tree_parser.index

Class type Pxp_tree_parser.index

class type [< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a]
index
= object .. end
The type of indexes over the ID attributes of the elements. This type is the minimum requirement needed by the parser to create such an index.

method add : string -> 'a Pxp_document.node -> unit
Add the passed node to the index. If there is already an ID with the passed string value, the exception Pxp_tree_parser.ID_not_unique can be raised. However, index implementations are free to also accept several identical IDs, although this does not comply to the standard.
method find : string -> 'a Pxp_document.node
Finds the node with the passed ID value, or raises Not_found
pxp-1.2.9/doc/manual/html/ref/type_Pxp_tree_parser.index.html0000644000175000017500000000610213055274551022725 0ustar gerdgerd PXP Reference : Pxp_tree_parser.index object
  method add :
    string ->
    (< clone : 'a; node : 'Pxp_document.node;
       set_node : 'Pxp_document.node -> unit; .. >
     as 'a)
    Pxp_document.node -> unit
  method find : string -> 'Pxp_document.node
end
pxp-1.2.9/doc/manual/html/ref/type_Pxp_tree_parser.html0000644000175000017500000002735313055274551021632 0ustar gerdgerd PXP Reference : Pxp_tree_parser sig
  exception ID_not_unique
  class type ['a] index =
    object
      constraint 'a =
        < clone : 'a; node : 'Pxp_document.node;
          set_node : 'Pxp_document.node -> unit; .. >
      method add : string -> 'Pxp_document.node -> unit
      method find : string -> 'Pxp_document.node
    end
  class ['a] hash_index :
    object
      constraint 'a =
        < clone : 'a; node : 'Pxp_document.node;
          set_node : 'Pxp_document.node -> unit; .. >
      method add : string -> 'Pxp_document.node -> unit
      method find : string -> 'Pxp_document.node
      method index : (string, 'Pxp_document.node) Hashtbl.t
    end
  val parse_document_entity :
    ?transform_dtd:(Pxp_dtd.dtd -> Pxp_dtd.dtd) ->
    ?id_index:(< clone : 'a; node : 'Pxp_document.node;
                 set_node : 'Pxp_document.node -> unit; .. >
               as 'a)
              Pxp_tree_parser.index ->
    Pxp_types.config ->
    Pxp_types.source -> 'Pxp_document.spec -> 'Pxp_document.document
  val parse_wfdocument_entity :
    ?transform_dtd:(Pxp_dtd.dtd -> Pxp_dtd.dtd) ->
    Pxp_types.config ->
    Pxp_types.source ->
    (< clone : 'a; node : 'Pxp_document.node;
       set_node : 'Pxp_document.node -> unit; .. >
     as 'a)
    Pxp_document.spec -> 'Pxp_document.document
  val parse_content_entity :
    ?id_index:(< clone : 'a; node : 'Pxp_document.node;
                 set_node : 'Pxp_document.node -> unit; .. >
               as 'a)
              Pxp_tree_parser.index ->
    Pxp_types.config ->
    Pxp_types.source ->
    Pxp_dtd.dtd -> 'Pxp_document.spec -> 'Pxp_document.node
  val parse_wfcontent_entity :
    Pxp_types.config ->
    Pxp_types.source ->
    (< clone : 'a; node : 'Pxp_document.node;
       set_node : 'Pxp_document.node -> unit; .. >
     as 'a)
    Pxp_document.spec -> 'Pxp_document.node
  val default_extension : 'Pxp_document.node Pxp_document.extension as 'a
  val default_spec :
    ('Pxp_document.node Pxp_document.extension as 'a) Pxp_document.spec
  val default_namespace_spec :
    ('Pxp_document.node Pxp_document.extension as 'a) Pxp_document.spec
end
pxp-1.2.9/doc/manual/html/ref/Pxp_core_types.html0000644000175000017500000000766413055274551020435 0ustar gerdgerd PXP Reference : Pxp_core_types

Module Pxp_core_types

module Pxp_core_types: sig .. end
This module is for internal use of PXP only. Users should refer to Pxp_types instead which exports the same types, exceptions, and values, plus a number of additional definitions.

module A: sig .. end
This is the type anchor
module type S = sig .. end
S is the signature of I, defined below.
module I: S 
An implementation of S.
pxp-1.2.9/doc/manual/html/ref/Pxp_core_types.A.html0000644000175000017500000004004413055274551020601 0ustar gerdgerd PXP Reference : Pxp_core_types.A

Module Pxp_core_types.A

module A: sig .. end
This is the type anchor


For documentation, see Pxp_core_types.S. This module defines some of the types mentioned in this module type.

User code must not refer directly to this module! The definitions are all also available in Pxp_types, and can be used from there!

module StringMap: Map.S  with type key = string
type ext_id = 
| System of string
| Public of (string * string)
| Anonymous
| Private of private_id
type private_id 
type resolver_id = {
   rid_private : private_id option;
   rid_public : string option;
   rid_system : string option;
   rid_system_base : string option;
}
type dtd_id = 
| External of ext_id
| Derived of ext_id
| Internal
type content_model_type = 
| Unspecified
| Empty
| Any
| Mixed of mixed_spec list
| Regexp of regexp_spec
type mixed_spec = 
| MPCDATA
| MChild of string
type regexp_spec = 
| Optional of regexp_spec
| Repeated of regexp_spec
| Repeated1 of regexp_spec
| Alt of regexp_spec list
| Seq of regexp_spec list
| Child of string
type att_type = 
| A_cdata
| A_id
| A_idref
| A_idrefs
| A_entity
| A_entities
| A_nmtoken
| A_nmtokens
| A_notation of string list
| A_enum of string list
type att_default = 
| D_required
| D_implied
| D_default of string
| D_fixed of string
type att_value = 
| Value of string
| Valuelist of string list
| Implied_value
type pool 
pxp-1.2.9/doc/manual/html/ref/Pxp_core_types.A.StringMap.html0000644000175000017500000000464613055274551022514 0ustar gerdgerd PXP Reference : Pxp_core_types.A.StringMap

Module Pxp_core_types.A.StringMap

module StringMap: Map.S  with type key = string

pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.A.StringMap.html0000644000175000017500000002412113055274551023543 0ustar gerdgerd PXP Reference : Pxp_core_types.A.StringMap sig
  type key = string
  type +'a t
  val empty : 'a t
  val is_empty : 'a t -> bool
  val mem : key -> 'a t -> bool
  val add : key -> '-> 'a t -> 'a t
  val singleton : key -> '-> 'a t
  val remove : key -> 'a t -> 'a t
  val merge :
    (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t
  val compare : ('-> '-> int) -> 'a t -> 'a t -> int
  val equal : ('-> '-> bool) -> 'a t -> 'a t -> bool
  val iter : (key -> '-> unit) -> 'a t -> unit
  val fold : (key -> '-> '-> 'b) -> 'a t -> '-> 'b
  val for_all : (key -> '-> bool) -> 'a t -> bool
  val exists : (key -> '-> bool) -> 'a t -> bool
  val filter : (key -> '-> bool) -> 'a t -> 'a t
  val partition : (key -> '-> bool) -> 'a t -> 'a t * 'a t
  val cardinal : 'a t -> int
  val bindings : 'a t -> (key * 'a) list
  val min_binding : 'a t -> key * 'a
  val max_binding : 'a t -> key * 'a
  val choose : 'a t -> key * 'a
  val split : key -> 'a t -> 'a t * 'a option * 'a t
  val find : key -> 'a t -> 'a
  val map : ('-> 'b) -> 'a t -> 'b t
  val mapi : (key -> '-> 'b) -> 'a t -> 'b t
end
pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.A.html0000644000175000017500000004307513055274551021651 0ustar gerdgerd PXP Reference : Pxp_core_types.A sig
  module StringMap :
    sig
      type key = string
      type +'a t
      val empty : 'a t
      val is_empty : 'a t -> bool
      val mem : key -> 'a t -> bool
      val add : key -> '-> 'a t -> 'a t
      val singleton : key -> '-> 'a t
      val remove : key -> 'a t -> 'a t
      val merge :
        (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t
      val compare : ('-> '-> int) -> 'a t -> 'a t -> int
      val equal : ('-> '-> bool) -> 'a t -> 'a t -> bool
      val iter : (key -> '-> unit) -> 'a t -> unit
      val fold : (key -> '-> '-> 'b) -> 'a t -> '-> 'b
      val for_all : (key -> '-> bool) -> 'a t -> bool
      val exists : (key -> '-> bool) -> 'a t -> bool
      val filter : (key -> '-> bool) -> 'a t -> 'a t
      val partition : (key -> '-> bool) -> 'a t -> 'a t * 'a t
      val cardinal : 'a t -> int
      val bindings : 'a t -> (key * 'a) list
      val min_binding : 'a t -> key * 'a
      val max_binding : 'a t -> key * 'a
      val choose : 'a t -> key * 'a
      val split : key -> 'a t -> 'a t * 'a option * 'a t
      val find : key -> 'a t -> 'a
      val map : ('-> 'b) -> 'a t -> 'b t
      val mapi : (key -> '-> 'b) -> 'a t -> 'b t
    end
  type ext_id =
      System of string
    | Public of (string * string)
    | Anonymous
    | Private of Pxp_core_types.A.private_id
  and private_id
  type resolver_id = {
    rid_private : Pxp_core_types.A.private_id option;
    rid_public : string option;
    rid_system : string option;
    rid_system_base : string option;
  }
  type dtd_id =
      External of Pxp_core_types.A.ext_id
    | Derived of Pxp_core_types.A.ext_id
    | Internal
  type content_model_type =
      Unspecified
    | Empty
    | Any
    | Mixed of Pxp_core_types.A.mixed_spec list
    | Regexp of Pxp_core_types.A.regexp_spec
  and mixed_spec = MPCDATA | MChild of string
  and regexp_spec =
      Optional of Pxp_core_types.A.regexp_spec
    | Repeated of Pxp_core_types.A.regexp_spec
    | Repeated1 of Pxp_core_types.A.regexp_spec
    | Alt of Pxp_core_types.A.regexp_spec list
    | Seq of Pxp_core_types.A.regexp_spec list
    | Child of string
  type att_type =
      A_cdata
    | A_id
    | A_idref
    | A_idrefs
    | A_entity
    | A_entities
    | A_nmtoken
    | A_nmtokens
    | A_notation of string list
    | A_enum of string list
  type att_default =
      D_required
    | D_implied
    | D_default of string
    | D_fixed of string
  type att_value = Value of string | Valuelist of string list | Implied_value
  type pool
end
pxp-1.2.9/doc/manual/html/ref/Pxp_core_types.I.html0000644000175000017500000012252313055274551020614 0ustar gerdgerd PXP Reference : Pxp_core_types.I

Module Pxp_core_types.I

module I: S 
An implementation of S.

User code must not refer directly to this module! The definitions are all also available in Pxp_types, and can be used from there!


module StringMap: Map.S  with type key = string
For maps with string keys

Identifiers


type ext_id = Pxp_core_types.A.ext_id = 
| System of string
| Public of (string * string)
| Anonymous
| Private of private_id
External identifiers are names for documents. A System identifier is a URL. PXP (without extensions) only supports file URLs in the form file:///directory/directory/.../file. Note that the percent encoding (% plus two hex digits) is supported in file URLs. A public identifier can be looked up in a catalog to find a local copy of the file; this type is mostly used for well-known documents (e.g. after standardization). A public identifier can be accompanied by a system identifier (Public(pubid,sysid)), but the system identifier can be the empty string. The value Anonymous should not be used to identify a real document; it is more thought as a placeholder when an ID is not yet known. Private identifiers are used by PXP internally. These identifiers have, unlike system or public IDs, no textual counterparts.

The identifiers are encoded as UTF-8 strings.

type private_id = Pxp_core_types.A.private_id 
A private ID is an opaque identifier
val allocate_private_id : unit -> private_id
Get a new unique private ID
type resolver_id = Pxp_core_types.A.resolver_id = {
   rid_private : private_id option;
   rid_public : string option;
   rid_system : string option;
   rid_system_base : string option;
}
A resolver ID is a version of external identifiers used during resolving (i.e. the process of mapping the identifier to a real resource). The same entity can have several names during resolving: one private ID, one public ID, and one system ID. For resolving system IDs, the base URL is also remembered (usually the system ID of the opener of the entity).
val resolver_id_of_ext_id : ext_id -> resolver_id
The standard way of converting an ext_id into a resolver ID. A System ID is turned into a resolver_id where only rid_system is set. A Public ID is turned into a resolver_id where both rid_public and rid_system are set. A Private ID is turned into a resolver_id where only rid_private is set. An Anonymous ID is turned into a resolver_id without any value (all components are None).
type dtd_id = Pxp_core_types.A.dtd_id = 
| External of ext_id (*DTD is completely external*)
| Derived of ext_id (*DTD is derived from an external DTD*)
| Internal (*DTD is completely internal*)
Identifier for DTDs

Content models (in DTDs)


type content_model_type = Pxp_core_types.A.content_model_type = 
| Unspecified (*A specification of the model has not yet been found*)
| Empty (*Nothing is allowed as content*)
| Any (*Everything is allowed as content*)
| Mixed of mixed_spec list (*The contents consist of elements and PCDATA in arbitrary order. What is allowed in particular is given as mixed_spec.*)
| Regexp of regexp_spec (*The contents are elements following this regular expression*)
Element declaration in a DTD
type mixed_spec = Pxp_core_types.A.mixed_spec = 
| MPCDATA (*PCDATA children are allowed*)
| MChild of string (*This kind of Element is allowed*)
Children of an element in "mixed"-style declaration
type regexp_spec = Pxp_core_types.A.regexp_spec = 
| Optional of regexp_spec (*subexpression?*)
| Repeated of regexp_spec (*subexpression**)
| Repeated1 of regexp_spec (*subexpression+*)
| Alt of regexp_spec list (*subexpr1 | subexpr2 | ... | subexprN*)
| Seq of regexp_spec list (*subexpr1 , subexpr2 , ... , subexprN*)
| Child of string (*This kind of Element is allowed here*)
Children of an element in a regexp-style declaration
type att_type = Pxp_core_types.A.att_type = 
| A_cdata (*CDATA*)
| A_id (*ID*)
| A_idref (*IDREF*)
| A_idrefs (*IDREFS*)
| A_entity (*ENTITY*)
| A_entities (*ENTITIES*)
| A_nmtoken (*NMTOKEN*)
| A_nmtokens (*NMTOKENS*)
| A_notation of string list (*NOTATION (name1 | name2 | ... | nameN)*)
| A_enum of string list (*(name1 | name2 | ... | nameN)*)
Attribute declaration in a DTD
type att_default = Pxp_core_types.A.att_default = 
| D_required (*#REQUIRED*)
| D_implied (*#IMPLIED*)
| D_default of string (*a value default -- the value is already expanded*)
| D_fixed of string (*FIXED value default -- the value is already expanded*)
Default value of an attribute

Attribute value


type att_value = Pxp_core_types.A.att_value = 
| Value of string
| Valuelist of string list
| Implied_value
Enumerates the possible values of an attribute:
  • Value s: The attribute is declared as a non-list type, or the attribute is undeclared; and the attribute is either defined with value "s", or it is missing but has the default value s.
  • [Valuelist [s1;...;sk]]: The attribute is declared as a list type, and the attribute is either defined with value "s1 ... sk" (space-separated words), or it is missing but has the default value "s1 ... sk".
  • Implied_value: The attribute is declared without default value, and there is no definition for the attribute.


Warnings


class type collect_warnings = object .. end
This object is sometimes used for outputting user warnings
class drop_warnings : collect_warnings
Drop any warnings
type warning = [ `W_XML_version_not_supported of string
| `W_code_point_cannot_be_represented of int
| `W_element_mentioned_but_not_declared of string
| `W_entity_declared_twice of string
| `W_multiple_ATTLIST_declarations of string
| `W_multiple_attribute_declarations of string * string
| `W_name_is_reserved_for_extensions of string ]
Kinds of warnings
class type symbolic_warnings = object .. end
This object is sometimes used for outputting user warnings
val string_of_warning : warning -> string
Turn the warning into a human-readable message
val warn : symbolic_warnings option ->
collect_warnings -> warning -> unit
Send a warning to the symbolic_warnings object, and then to the collect_warnings object.

Encoding


type encoding = Netconversion.encoding 
For the representation of external resources (files etc.) we accept all encodings for character sets which are defined in Netconversion (package netstring).
type rep_encoding = [ `Enc_cp1006
| `Enc_cp437
| `Enc_cp737
| `Enc_cp775
| `Enc_cp850
| `Enc_cp852
| `Enc_cp855
| `Enc_cp856
| `Enc_cp857
| `Enc_cp860
| `Enc_cp861
| `Enc_cp862
| `Enc_cp863
| `Enc_cp864
| `Enc_cp865
| `Enc_cp866
| `Enc_cp869
| `Enc_cp874
| `Enc_iso88591
| `Enc_iso885910
| `Enc_iso885913
| `Enc_iso885914
| `Enc_iso885915
| `Enc_iso885916
| `Enc_iso88592
| `Enc_iso88593
| `Enc_iso88594
| `Enc_iso88595
| `Enc_iso88596
| `Enc_iso88597
| `Enc_iso88598
| `Enc_iso88599
| `Enc_koi8r
| `Enc_macroman
| `Enc_usascii
| `Enc_utf8
| `Enc_windows1250
| `Enc_windows1251
| `Enc_windows1252
| `Enc_windows1253
| `Enc_windows1254
| `Enc_windows1255
| `Enc_windows1256
| `Enc_windows1257
| `Enc_windows1258 ]
The subset of encoding that may be used for the internal representation of strings. The common property of the following encodings is that they are ASCII-compatible - the PXP code relies on that.

Exceptions


exception Validation_error of string
Violation of a validity constraint
exception WF_error of string
Violation of a well-formedness constraint
exception Namespace_error of string
Violation of a namespace constraint
exception Error of string
Other error
exception Character_not_supported
exception At of (string * exn)
The string is a description where the exn happened. The exn value can again be At(_,_) (for example, when an entity within an entity causes the error).
exception Undeclared
Indicates that no declaration is available and because of this every kind of usage is allowed. (Raised by some DTD methods.)
exception Method_not_applicable of string
Indicates that a method has been called that is not applicable for the class. The argument is the name of the method.
exception Namespace_method_not_applicable of string
Indicates that the called method is a namespace method but that the object does not support namespaces. The argument is the name of the method.
exception Not_competent
The resolver cannot open this kind of entity ID
exception Not_resolvable of exn
While opening the entity, the nested exception occurred
exception Namespace_not_managed of string
A namespace URI is used but not declared in the namespace manager. The string argument is the URI in question.
exception Namespace_prefix_not_managed of string
A namespace prefix is used but not declared in the namespace manager. The string argument is the prefix in question.
exception Namespace_not_in_scope of string
The namespace scope does not know the URI
val string_of_exn : exn -> string
Converts a PXP exception into a readable string

Output destination


type output_stream = [ `Out_buffer of Buffer.t
| `Out_channel of Pervasives.out_channel
| `Out_function of string -> int -> int -> unit
| `Out_netchannel of Netchannels.out_obj_channel ]
Designates an output destination for several printers:
  • `Out_buffer b: Output to buffer b
  • `Out_channel ch: Output to channel ch
  • `Out_function f: Output to function f. The function f is used like Pervasives.output_string.
  • `Out_netchannel n: Output to the ocamlnet channel n

val write : output_stream -> string -> int -> int -> unit
write os s pos len: Writes the string (portion) to the buffer/channel/stream

Pools


type pool = Pxp_core_types.A.pool 
A pool designates a way to increase string sharing
val make_probabilistic_pool : ?fraction:float -> int -> pool
A probalistic string pool tries to map strings to pool strings in order to make it more likely that equal strings are stored in the same memory block. The int argument is the size of the pool; this is the number of entries of the pool. However, not all entries of the pool are used; the fraction argument (default: 0.3) determines the fraction of the actually used entries. The higher the fraction is, the more strings can be managed at the same time; the lower the fraction is, the more likely it is that a new string can be added to the pool.
val pool_string : pool -> string -> string
Tries to find the passed string in the pool; if the string is in the pool, the pool string is returned. Otherwise, the function tries to add the passed string to the pool, and the passed string is returned.
pxp-1.2.9/doc/manual/html/ref/Pxp_core_types.S.StringMap.html0000644000175000017500000000475113055274551022533 0ustar gerdgerd PXP Reference : Pxp_core_types.S.StringMap

Module Pxp_core_types.S.StringMap

module StringMap: Map.S  with type key = string
For maps with string keys

pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.S.StringMap.html0000644000175000017500000002412113055274551023565 0ustar gerdgerd PXP Reference : Pxp_core_types.S.StringMap sig
  type key = string
  type +'a t
  val empty : 'a t
  val is_empty : 'a t -> bool
  val mem : key -> 'a t -> bool
  val add : key -> '-> 'a t -> 'a t
  val singleton : key -> '-> 'a t
  val remove : key -> 'a t -> 'a t
  val merge :
    (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t
  val compare : ('-> '-> int) -> 'a t -> 'a t -> int
  val equal : ('-> '-> bool) -> 'a t -> 'a t -> bool
  val iter : (key -> '-> unit) -> 'a t -> unit
  val fold : (key -> '-> '-> 'b) -> 'a t -> '-> 'b
  val for_all : (key -> '-> bool) -> 'a t -> bool
  val exists : (key -> '-> bool) -> 'a t -> bool
  val filter : (key -> '-> bool) -> 'a t -> 'a t
  val partition : (key -> '-> bool) -> 'a t -> 'a t * 'a t
  val cardinal : 'a t -> int
  val bindings : 'a t -> (key * 'a) list
  val min_binding : 'a t -> key * 'a
  val max_binding : 'a t -> key * 'a
  val choose : 'a t -> key * 'a
  val split : key -> 'a t -> 'a t * 'a option * 'a t
  val find : key -> 'a t -> 'a
  val map : ('-> 'b) -> 'a t -> 'b t
  val mapi : (key -> '-> 'b) -> 'a t -> 'b t
end
pxp-1.2.9/doc/manual/html/ref/Pxp_core_types.S.drop_warnings-c.html0000644000175000017500000000507713055274551023725 0ustar gerdgerd PXP Reference : Pxp_core_types.S.drop_warnings

Class Pxp_core_types.S.drop_warnings

class drop_warnings : collect_warnings
Drop any warnings

pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.S.drop_warnings.html0000644000175000017500000000411313055274551024534 0ustar gerdgerd PXP Reference : Pxp_core_types.S.drop_warnings Pxp_core_types.S.collect_warningspxp-1.2.9/doc/manual/html/ref/Pxp_core_types.S.collect_warnings-c.html0000644000175000017500000000575613055274551024412 0ustar gerdgerd PXP Reference : Pxp_core_types.S.collect_warnings

Class type Pxp_core_types.S.collect_warnings

class type collect_warnings = object .. end
This object is sometimes used for outputting user warnings

method warn : string -> unit
pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.S.collect_warnings.html0000644000175000017500000000426013055274551025220 0ustar gerdgerd PXP Reference : Pxp_core_types.S.collect_warnings object method warn : string -> unit endpxp-1.2.9/doc/manual/html/ref/Pxp_core_types.S.symbolic_warnings-c.html0000644000175000017500000000605113055274551024573 0ustar gerdgerd PXP Reference : Pxp_core_types.S.symbolic_warnings

Class type Pxp_core_types.S.symbolic_warnings

class type symbolic_warnings = object .. end
This object is sometimes used for outputting user warnings

method warn : warning -> unit
pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.S.symbolic_warnings.html0000644000175000017500000000440513055274551025415 0ustar gerdgerd PXP Reference : Pxp_core_types.S.symbolic_warnings object method warn : Pxp_core_types.S.warning -> unit endpxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.I.html0000644000175000017500000000377413055274551021663 0ustar gerdgerd PXP Reference : Pxp_core_types.I Spxp-1.2.9/doc/manual/html/ref/Pxp_core_types.S.html0000644000175000017500000012303213055274551020622 0ustar gerdgerd PXP Reference : Pxp_core_types.S

Module type Pxp_core_types.S

module type S = sig .. end
S is the signature of I, defined below. S is also included into the interface of Pxp_types.

User code must not refer directly to this module type! The definitions are all also available in Pxp_types, and can be used from there!


module StringMap: Map.S  with type key = string
For maps with string keys

Identifiers


type ext_id = Pxp_core_types.A.ext_id = 
| System of string
| Public of (string * string)
| Anonymous
| Private of private_id
External identifiers are names for documents. A System identifier is a URL. PXP (without extensions) only supports file URLs in the form file:///directory/directory/.../file. Note that the percent encoding (% plus two hex digits) is supported in file URLs. A public identifier can be looked up in a catalog to find a local copy of the file; this type is mostly used for well-known documents (e.g. after standardization). A public identifier can be accompanied by a system identifier (Public(pubid,sysid)), but the system identifier can be the empty string. The value Anonymous should not be used to identify a real document; it is more thought as a placeholder when an ID is not yet known. Private identifiers are used by PXP internally. These identifiers have, unlike system or public IDs, no textual counterparts.

The identifiers are encoded as UTF-8 strings.

type private_id = Pxp_core_types.A.private_id 
A private ID is an opaque identifier
val allocate_private_id : unit -> private_id
Get a new unique private ID
type resolver_id = Pxp_core_types.A.resolver_id = {
   rid_private : private_id option;
   rid_public : string option;
   rid_system : string option;
   rid_system_base : string option;
}
A resolver ID is a version of external identifiers used during resolving (i.e. the process of mapping the identifier to a real resource). The same entity can have several names during resolving: one private ID, one public ID, and one system ID. For resolving system IDs, the base URL is also remembered (usually the system ID of the opener of the entity).
val resolver_id_of_ext_id : ext_id -> resolver_id
The standard way of converting an ext_id into a resolver ID. A System ID is turned into a resolver_id where only rid_system is set. A Public ID is turned into a resolver_id where both rid_public and rid_system are set. A Private ID is turned into a resolver_id where only rid_private is set. An Anonymous ID is turned into a resolver_id without any value (all components are None).
type dtd_id = Pxp_core_types.A.dtd_id = 
| External of ext_id (*DTD is completely external*)
| Derived of ext_id (*DTD is derived from an external DTD*)
| Internal (*DTD is completely internal*)
Identifier for DTDs

Content models (in DTDs)


type content_model_type = Pxp_core_types.A.content_model_type = 
| Unspecified (*A specification of the model has not yet been found*)
| Empty (*Nothing is allowed as content*)
| Any (*Everything is allowed as content*)
| Mixed of mixed_spec list (*The contents consist of elements and PCDATA in arbitrary order. What is allowed in particular is given as mixed_spec.*)
| Regexp of regexp_spec (*The contents are elements following this regular expression*)
Element declaration in a DTD
type mixed_spec = Pxp_core_types.A.mixed_spec = 
| MPCDATA (*PCDATA children are allowed*)
| MChild of string (*This kind of Element is allowed*)
Children of an element in "mixed"-style declaration
type regexp_spec = Pxp_core_types.A.regexp_spec = 
| Optional of regexp_spec (*subexpression?*)
| Repeated of regexp_spec (*subexpression**)
| Repeated1 of regexp_spec (*subexpression+*)
| Alt of regexp_spec list (*subexpr1 | subexpr2 | ... | subexprN*)
| Seq of regexp_spec list (*subexpr1 , subexpr2 , ... , subexprN*)
| Child of string (*This kind of Element is allowed here*)
Children of an element in a regexp-style declaration
type att_type = Pxp_core_types.A.att_type = 
| A_cdata (*CDATA*)
| A_id (*ID*)
| A_idref (*IDREF*)
| A_idrefs (*IDREFS*)
| A_entity (*ENTITY*)
| A_entities (*ENTITIES*)
| A_nmtoken (*NMTOKEN*)
| A_nmtokens (*NMTOKENS*)
| A_notation of string list (*NOTATION (name1 | name2 | ... | nameN)*)
| A_enum of string list (*(name1 | name2 | ... | nameN)*)
Attribute declaration in a DTD
type att_default = Pxp_core_types.A.att_default = 
| D_required (*#REQUIRED*)
| D_implied (*#IMPLIED*)
| D_default of string (*a value default -- the value is already expanded*)
| D_fixed of string (*FIXED value default -- the value is already expanded*)
Default value of an attribute

Attribute value


type att_value = Pxp_core_types.A.att_value = 
| Value of string
| Valuelist of string list
| Implied_value
Enumerates the possible values of an attribute:
  • Value s: The attribute is declared as a non-list type, or the attribute is undeclared; and the attribute is either defined with value "s", or it is missing but has the default value s.
  • [Valuelist [s1;...;sk]]: The attribute is declared as a list type, and the attribute is either defined with value "s1 ... sk" (space-separated words), or it is missing but has the default value "s1 ... sk".
  • Implied_value: The attribute is declared without default value, and there is no definition for the attribute.


Warnings


class type collect_warnings = object .. end
This object is sometimes used for outputting user warnings
class drop_warnings : collect_warnings
Drop any warnings
type warning = [ `W_XML_version_not_supported of string
| `W_code_point_cannot_be_represented of int
| `W_element_mentioned_but_not_declared of string
| `W_entity_declared_twice of string
| `W_multiple_ATTLIST_declarations of string
| `W_multiple_attribute_declarations of string * string
| `W_name_is_reserved_for_extensions of string ]
Kinds of warnings
class type symbolic_warnings = object .. end
This object is sometimes used for outputting user warnings
val string_of_warning : warning -> string
Turn the warning into a human-readable message
val warn : symbolic_warnings option ->
collect_warnings -> warning -> unit
Send a warning to the symbolic_warnings object, and then to the collect_warnings object.

Encoding


type encoding = Netconversion.encoding 
For the representation of external resources (files etc.) we accept all encodings for character sets which are defined in Netconversion (package netstring).
type rep_encoding = [ `Enc_cp1006
| `Enc_cp437
| `Enc_cp737
| `Enc_cp775
| `Enc_cp850
| `Enc_cp852
| `Enc_cp855
| `Enc_cp856
| `Enc_cp857
| `Enc_cp860
| `Enc_cp861
| `Enc_cp862
| `Enc_cp863
| `Enc_cp864
| `Enc_cp865
| `Enc_cp866
| `Enc_cp869
| `Enc_cp874
| `Enc_iso88591
| `Enc_iso885910
| `Enc_iso885913
| `Enc_iso885914
| `Enc_iso885915
| `Enc_iso885916
| `Enc_iso88592
| `Enc_iso88593
| `Enc_iso88594
| `Enc_iso88595
| `Enc_iso88596
| `Enc_iso88597
| `Enc_iso88598
| `Enc_iso88599
| `Enc_koi8r
| `Enc_macroman
| `Enc_usascii
| `Enc_utf8
| `Enc_windows1250
| `Enc_windows1251
| `Enc_windows1252
| `Enc_windows1253
| `Enc_windows1254
| `Enc_windows1255
| `Enc_windows1256
| `Enc_windows1257
| `Enc_windows1258 ]
The subset of encoding that may be used for the internal representation of strings. The common property of the following encodings is that they are ASCII-compatible - the PXP code relies on that.

Exceptions


exception Validation_error of string
Violation of a validity constraint
exception WF_error of string
Violation of a well-formedness constraint
exception Namespace_error of string
Violation of a namespace constraint
exception Error of string
Other error
exception Character_not_supported
exception At of (string * exn)
The string is a description where the exn happened. The exn value can again be At(_,_) (for example, when an entity within an entity causes the error).
exception Undeclared
Indicates that no declaration is available and because of this every kind of usage is allowed. (Raised by some DTD methods.)
exception Method_not_applicable of string
Indicates that a method has been called that is not applicable for the class. The argument is the name of the method.
exception Namespace_method_not_applicable of string
Indicates that the called method is a namespace method but that the object does not support namespaces. The argument is the name of the method.
exception Not_competent
The resolver cannot open this kind of entity ID
exception Not_resolvable of exn
While opening the entity, the nested exception occurred
exception Namespace_not_managed of string
A namespace URI is used but not declared in the namespace manager. The string argument is the URI in question.
exception Namespace_prefix_not_managed of string
A namespace prefix is used but not declared in the namespace manager. The string argument is the prefix in question.
exception Namespace_not_in_scope of string
The namespace scope does not know the URI
val string_of_exn : exn -> string
Converts a PXP exception into a readable string

Output destination


type output_stream = [ `Out_buffer of Buffer.t
| `Out_channel of Pervasives.out_channel
| `Out_function of string -> int -> int -> unit
| `Out_netchannel of Netchannels.out_obj_channel ]
Designates an output destination for several printers:
  • `Out_buffer b: Output to buffer b
  • `Out_channel ch: Output to channel ch
  • `Out_function f: Output to function f. The function f is used like Pervasives.output_string.
  • `Out_netchannel n: Output to the ocamlnet channel n

val write : output_stream -> string -> int -> int -> unit
write os s pos len: Writes the string (portion) to the buffer/channel/stream

Pools


type pool = Pxp_core_types.A.pool 
A pool designates a way to increase string sharing
val make_probabilistic_pool : ?fraction:float -> int -> pool
A probalistic string pool tries to map strings to pool strings in order to make it more likely that equal strings are stored in the same memory block. The int argument is the size of the pool; this is the number of entries of the pool. However, not all entries of the pool are used; the fraction argument (default: 0.3) determines the fraction of the actually used entries. The higher the fraction is, the more strings can be managed at the same time; the lower the fraction is, the more likely it is that a new string can be added to the pool.
val pool_string : pool -> string -> string
Tries to find the passed string in the pool; if the string is in the pool, the pool string is returned. Otherwise, the function tries to add the passed string to the pool, and the passed string is returned.
pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.S.html0000644000175000017500000010435413055274551021671 0ustar gerdgerd PXP Reference : Pxp_core_types.S sig
  module StringMap :
    sig
      type key = string
      type +'a t
      val empty : 'a t
      val is_empty : 'a t -> bool
      val mem : key -> 'a t -> bool
      val add : key -> '-> 'a t -> 'a t
      val singleton : key -> '-> 'a t
      val remove : key -> 'a t -> 'a t
      val merge :
        (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t
      val compare : ('-> '-> int) -> 'a t -> 'a t -> int
      val equal : ('-> '-> bool) -> 'a t -> 'a t -> bool
      val iter : (key -> '-> unit) -> 'a t -> unit
      val fold : (key -> '-> '-> 'b) -> 'a t -> '-> 'b
      val for_all : (key -> '-> bool) -> 'a t -> bool
      val exists : (key -> '-> bool) -> 'a t -> bool
      val filter : (key -> '-> bool) -> 'a t -> 'a t
      val partition : (key -> '-> bool) -> 'a t -> 'a t * 'a t
      val cardinal : 'a t -> int
      val bindings : 'a t -> (key * 'a) list
      val min_binding : 'a t -> key * 'a
      val max_binding : 'a t -> key * 'a
      val choose : 'a t -> key * 'a
      val split : key -> 'a t -> 'a t * 'a option * 'a t
      val find : key -> 'a t -> 'a
      val map : ('-> 'b) -> 'a t -> 'b t
      val mapi : (key -> '-> 'b) -> 'a t -> 'b t
    end
  type ext_id =
    Pxp_core_types.A.ext_id =
      System of string
    | Public of (string * string)
    | Anonymous
    | Private of Pxp_core_types.S.private_id
  and private_id = Pxp_core_types.A.private_id
  val allocate_private_id : unit -> Pxp_core_types.S.private_id
  type resolver_id =
    Pxp_core_types.A.resolver_id = {
    rid_private : Pxp_core_types.S.private_id option;
    rid_public : string option;
    rid_system : string option;
    rid_system_base : string option;
  }
  val resolver_id_of_ext_id :
    Pxp_core_types.S.ext_id -> Pxp_core_types.S.resolver_id
  type dtd_id =
    Pxp_core_types.A.dtd_id =
      External of Pxp_core_types.S.ext_id
    | Derived of Pxp_core_types.S.ext_id
    | Internal
  type content_model_type =
    Pxp_core_types.A.content_model_type =
      Unspecified
    | Empty
    | Any
    | Mixed of Pxp_core_types.S.mixed_spec list
    | Regexp of Pxp_core_types.S.regexp_spec
  and mixed_spec = Pxp_core_types.A.mixed_spec = MPCDATA | MChild of string
  and regexp_spec =
    Pxp_core_types.A.regexp_spec =
      Optional of Pxp_core_types.S.regexp_spec
    | Repeated of Pxp_core_types.S.regexp_spec
    | Repeated1 of Pxp_core_types.S.regexp_spec
    | Alt of Pxp_core_types.S.regexp_spec list
    | Seq of Pxp_core_types.S.regexp_spec list
    | Child of string
  type att_type =
    Pxp_core_types.A.att_type =
      A_cdata
    | A_id
    | A_idref
    | A_idrefs
    | A_entity
    | A_entities
    | A_nmtoken
    | A_nmtokens
    | A_notation of string list
    | A_enum of string list
  type att_default =
    Pxp_core_types.A.att_default =
      D_required
    | D_implied
    | D_default of string
    | D_fixed of string
  type att_value =
    Pxp_core_types.A.att_value =
      Value of string
    | Valuelist of string list
    | Implied_value
  class type collect_warnings = object method warn : string -> unit end
  class drop_warnings : collect_warnings
  type warning =
      [ `W_XML_version_not_supported of string
      | `W_code_point_cannot_be_represented of int
      | `W_element_mentioned_but_not_declared of string
      | `W_entity_declared_twice of string
      | `W_multiple_ATTLIST_declarations of string
      | `W_multiple_attribute_declarations of string * string
      | `W_name_is_reserved_for_extensions of string ]
  class type symbolic_warnings =
    object method warn : Pxp_core_types.S.warning -> unit end
  val string_of_warning : Pxp_core_types.S.warning -> string
  val warn :
    Pxp_core_types.S.symbolic_warnings option ->
    Pxp_core_types.S.collect_warnings -> Pxp_core_types.S.warning -> unit
  type encoding = Netconversion.encoding
  type rep_encoding =
      [ `Enc_cp1006
      | `Enc_cp437
      | `Enc_cp737
      | `Enc_cp775
      | `Enc_cp850
      | `Enc_cp852
      | `Enc_cp855
      | `Enc_cp856
      | `Enc_cp857
      | `Enc_cp860
      | `Enc_cp861
      | `Enc_cp862
      | `Enc_cp863
      | `Enc_cp864
      | `Enc_cp865
      | `Enc_cp866
      | `Enc_cp869
      | `Enc_cp874
      | `Enc_iso88591
      | `Enc_iso885910
      | `Enc_iso885913
      | `Enc_iso885914
      | `Enc_iso885915
      | `Enc_iso885916
      | `Enc_iso88592
      | `Enc_iso88593
      | `Enc_iso88594
      | `Enc_iso88595
      | `Enc_iso88596
      | `Enc_iso88597
      | `Enc_iso88598
      | `Enc_iso88599
      | `Enc_koi8r
      | `Enc_macroman
      | `Enc_usascii
      | `Enc_utf8
      | `Enc_windows1250
      | `Enc_windows1251
      | `Enc_windows1252
      | `Enc_windows1253
      | `Enc_windows1254
      | `Enc_windows1255
      | `Enc_windows1256
      | `Enc_windows1257
      | `Enc_windows1258 ]
  exception Validation_error of string
  exception WF_error of string
  exception Namespace_error of string
  exception Error of string
  exception Character_not_supported
  exception At of (string * exn)
  exception Undeclared
  exception Method_not_applicable of string
  exception Namespace_method_not_applicable of string
  exception Not_competent
  exception Not_resolvable of exn
  exception Namespace_not_managed of string
  exception Namespace_prefix_not_managed of string
  exception Namespace_not_in_scope of string
  val string_of_exn : exn -> string
  type output_stream =
      [ `Out_buffer of Buffer.t
      | `Out_channel of Pervasives.out_channel
      | `Out_function of string -> int -> int -> unit
      | `Out_netchannel of Netchannels.out_obj_channel ]
  val write : Pxp_core_types.S.output_stream -> string -> int -> int -> unit
  type pool = Pxp_core_types.A.pool
  val make_probabilistic_pool :
    ?fraction:float -> int -> Pxp_core_types.S.pool
  val pool_string : Pxp_core_types.S.pool -> string -> string
end
pxp-1.2.9/doc/manual/html/ref/type_Pxp_core_types.html0000644000175000017500000016157313055274551021476 0ustar gerdgerd PXP Reference : Pxp_core_types sig
  module A :
    sig
      module StringMap :
        sig
          type key = string
          type +'a t
          val empty : 'a t
          val is_empty : 'a t -> bool
          val mem : key -> 'a t -> bool
          val add : key -> '-> 'a t -> 'a t
          val singleton : key -> '-> 'a t
          val remove : key -> 'a t -> 'a t
          val merge :
            (key -> 'a option -> 'b option -> 'c option) ->
            'a t -> 'b t -> 'c t
          val compare : ('-> '-> int) -> 'a t -> 'a t -> int
          val equal : ('-> '-> bool) -> 'a t -> 'a t -> bool
          val iter : (key -> '-> unit) -> 'a t -> unit
          val fold : (key -> '-> '-> 'b) -> 'a t -> '-> 'b
          val for_all : (key -> '-> bool) -> 'a t -> bool
          val exists : (key -> '-> bool) -> 'a t -> bool
          val filter : (key -> '-> bool) -> 'a t -> 'a t
          val partition : (key -> '-> bool) -> 'a t -> 'a t * 'a t
          val cardinal : 'a t -> int
          val bindings : 'a t -> (key * 'a) list
          val min_binding : 'a t -> key * 'a
          val max_binding : 'a t -> key * 'a
          val choose : 'a t -> key * 'a
          val split : key -> 'a t -> 'a t * 'a option * 'a t
          val find : key -> 'a t -> 'a
          val map : ('-> 'b) -> 'a t -> 'b t
          val mapi : (key -> '-> 'b) -> 'a t -> 'b t
        end
      type ext_id =
          System of string
        | Public of (string * string)
        | Anonymous
        | Private of Pxp_core_types.A.private_id
      and private_id
      type resolver_id = {
        rid_private : Pxp_core_types.A.private_id option;
        rid_public : string option;
        rid_system : string option;
        rid_system_base : string option;
      }
      type dtd_id =
          External of Pxp_core_types.A.ext_id
        | Derived of Pxp_core_types.A.ext_id
        | Internal
      type content_model_type =
          Unspecified
        | Empty
        | Any
        | Mixed of Pxp_core_types.A.mixed_spec list
        | Regexp of Pxp_core_types.A.regexp_spec
      and mixed_spec = MPCDATA | MChild of string
      and regexp_spec =
          Optional of Pxp_core_types.A.regexp_spec
        | Repeated of Pxp_core_types.A.regexp_spec
        | Repeated1 of Pxp_core_types.A.regexp_spec
        | Alt of Pxp_core_types.A.regexp_spec list
        | Seq of Pxp_core_types.A.regexp_spec list
        | Child of string
      type att_type =
          A_cdata
        | A_id
        | A_idref
        | A_idrefs
        | A_entity
        | A_entities
        | A_nmtoken
        | A_nmtokens
        | A_notation of string list
        | A_enum of string list
      type att_default =
          D_required
        | D_implied
        | D_default of string
        | D_fixed of string
      type att_value =
          Value of string
        | Valuelist of string list
        | Implied_value
      type pool
    end
  module type S =
    sig
      module StringMap :
        sig
          type key = string
          type +'a t
          val empty : 'a t
          val is_empty : 'a t -> bool
          val mem : key -> 'a t -> bool
          val add : key -> '-> 'a t -> 'a t
          val singleton : key -> '-> 'a t
          val remove : key -> 'a t -> 'a t
          val merge :
            (key -> 'a option -> 'b option -> 'c option) ->
            'a t -> 'b t -> 'c t
          val compare : ('-> '-> int) -> 'a t -> 'a t -> int
          val equal : ('-> '-> bool) -> 'a t -> 'a t -> bool
          val iter : (key -> '-> unit) -> 'a t -> unit
          val fold : (key -> '-> '-> 'b) -> 'a t -> '-> 'b
          val for_all : (key -> '-> bool) -> 'a t -> bool
          val exists : (key -> '-> bool) -> 'a t -> bool
          val filter : (key -> '-> bool) -> 'a t -> 'a t
          val partition : (key -> '-> bool) -> 'a t -> 'a t * 'a t
          val cardinal : 'a t -> int
          val bindings : 'a t -> (key * 'a) list
          val min_binding : 'a t -> key * 'a
          val max_binding : 'a t -> key * 'a
          val choose : 'a t -> key * 'a
          val split : key -> 'a t -> 'a t * 'a option * 'a t
          val find : key -> 'a t -> 'a
          val map : ('-> 'b) -> 'a t -> 'b t
          val mapi : (key -> '-> 'b) -> 'a t -> 'b t
        end
      type ext_id =
        Pxp_core_types.A.ext_id =
          System of string
        | Public of (string * string)
        | Anonymous
        | Private of Pxp_core_types.S.private_id
      and private_id = Pxp_core_types.A.private_id
      val allocate_private_id : unit -> Pxp_core_types.S.private_id
      type resolver_id =
        Pxp_core_types.A.resolver_id = {
        rid_private : Pxp_core_types.S.private_id option;
        rid_public : string option;
        rid_system : string option;
        rid_system_base : string option;
      }
      val resolver_id_of_ext_id :
        Pxp_core_types.S.ext_id -> Pxp_core_types.S.resolver_id
      type dtd_id =
        Pxp_core_types.A.dtd_id =
          External of Pxp_core_types.S.ext_id
        | Derived of Pxp_core_types.S.ext_id
        | Internal
      type content_model_type =
        Pxp_core_types.A.content_model_type =
          Unspecified
        | Empty
        | Any
        | Mixed of Pxp_core_types.S.mixed_spec list
        | Regexp of Pxp_core_types.S.regexp_spec
      and mixed_spec =
        Pxp_core_types.A.mixed_spec =
          MPCDATA
        | MChild of string
      and regexp_spec =
        Pxp_core_types.A.regexp_spec =
          Optional of Pxp_core_types.S.regexp_spec
        | Repeated of Pxp_core_types.S.regexp_spec
        | Repeated1 of Pxp_core_types.S.regexp_spec
        | Alt of Pxp_core_types.S.regexp_spec list
        | Seq of Pxp_core_types.S.regexp_spec list
        | Child of string
      type att_type =
        Pxp_core_types.A.att_type =
          A_cdata
        | A_id
        | A_idref
        | A_idrefs
        | A_entity
        | A_entities
        | A_nmtoken
        | A_nmtokens
        | A_notation of string list
        | A_enum of string list
      type att_default =
        Pxp_core_types.A.att_default =
          D_required
        | D_implied
        | D_default of string
        | D_fixed of string
      type att_value =
        Pxp_core_types.A.att_value =
          Value of string
        | Valuelist of string list
        | Implied_value
      class type collect_warnings = object method warn : string -> unit end
      class drop_warnings : collect_warnings
      type warning =
          [ `W_XML_version_not_supported of string
          | `W_code_point_cannot_be_represented of int
          | `W_element_mentioned_but_not_declared of string
          | `W_entity_declared_twice of string
          | `W_multiple_ATTLIST_declarations of string
          | `W_multiple_attribute_declarations of string * string
          | `W_name_is_reserved_for_extensions of string ]
      class type symbolic_warnings =
        object method warn : Pxp_core_types.S.warning -> unit end
      val string_of_warning : Pxp_core_types.S.warning -> string
      val warn :
        Pxp_core_types.S.symbolic_warnings option ->
        Pxp_core_types.S.collect_warnings -> Pxp_core_types.S.warning -> unit
      type encoding = Netconversion.encoding
      type rep_encoding =
          [ `Enc_cp1006
          | `Enc_cp437
          | `Enc_cp737
          | `Enc_cp775
          | `Enc_cp850
          | `Enc_cp852
          | `Enc_cp855
          | `Enc_cp856
          | `Enc_cp857
          | `Enc_cp860
          | `Enc_cp861
          | `Enc_cp862
          | `Enc_cp863
          | `Enc_cp864
          | `Enc_cp865
          | `Enc_cp866
          | `Enc_cp869
          | `Enc_cp874
          | `Enc_iso88591
          | `Enc_iso885910
          | `Enc_iso885913
          | `Enc_iso885914
          | `Enc_iso885915
          | `Enc_iso885916
          | `Enc_iso88592
          | `Enc_iso88593
          | `Enc_iso88594
          | `Enc_iso88595
          | `Enc_iso88596
          | `Enc_iso88597
          | `Enc_iso88598
          | `Enc_iso88599
          | `Enc_koi8r
          | `Enc_macroman
          | `Enc_usascii
          | `Enc_utf8
          | `Enc_windows1250
          | `Enc_windows1251
          | `Enc_windows1252
          | `Enc_windows1253
          | `Enc_windows1254
          | `Enc_windows1255
          | `Enc_windows1256
          | `Enc_windows1257
          | `Enc_windows1258 ]
      exception Validation_error of string
      exception WF_error of string
      exception Namespace_error of string
      exception Error of string
      exception Character_not_supported
      exception At of (string * exn)
      exception Undeclared
      exception Method_not_applicable of string
      exception Namespace_method_not_applicable of string
      exception Not_competent
      exception Not_resolvable of exn
      exception Namespace_not_managed of string
      exception Namespace_prefix_not_managed of string
      exception Namespace_not_in_scope of string
      val string_of_exn : exn -> string
      type output_stream =
          [ `Out_buffer of Buffer.t
          | `Out_channel of Pervasives.out_channel
          | `Out_function of string -> int -> int -> unit
          | `Out_netchannel of Netchannels.out_obj_channel ]
      val write :
        Pxp_core_types.S.output_stream -> string -> int -> int -> unit
      type pool = Pxp_core_types.A.pool
      val make_probabilistic_pool :
        ?fraction:float -> int -> Pxp_core_types.S.pool
      val pool_string : Pxp_core_types.S.pool -> string -> string
    end
  module I : S
end
pxp-1.2.9/doc/manual/html/ref/Pxp_ev_parser.html0000644000175000017500000003417113055274551020240 0ustar gerdgerd PXP Reference : Pxp_ev_parser

Module Pxp_ev_parser

module Pxp_ev_parser: sig .. end
Calling the parser in event mode


In event parsing, the parser generates a stream of events while reading XML text (one or several files). In "push mode" the user provides a callback function, and the parser invokes this function for every event. In "pull mode", the parser creates a function that fetches the next event of the stream, and that can be repeatedly be called by the user to get one event after the other.

For an introduction into this type of parsing, see Intro_events. In Pxp_event you find functions for composing, analyzing and transforming streams of events (for pull mode). For converting a stream of events into a tree, see Pxp_document.solidify. For converting a tree into a stream of events, see Pxp_document.liquefy.

val create_entity_manager : ?is_document:bool ->
Pxp_types.config -> Pxp_types.source -> Pxp_entity_manager.entity_manager
Creates an entity manager that is initialized with the toplevel entity referenced by the source argument. The entity manager can be used by process_entity below.

The following configuration options are interpreted:

  • warner
  • encoding
  • debugging_mode
is_document: true, the default, sets that the entity to read is a complete document, and false sets that it is only a fragment. The value true enforces several restrictions on document entities, e.g. that <![INCLUDE[..]]> and <![IGNORE[..]]> are not allowed and that additional nesting rules are respected by parameter entities.
val process_entity : Pxp_types.config ->
Pxp_types.entry ->
Pxp_entity_manager.entity_manager -> (Pxp_types.event -> unit) -> unit
Parses a document or a document fragment in push mode. At least the well-formedness of the document is checked, but the flags of the entry argument may specify more.

While parsing, events are generated and the passed function is called for every event. The parsed text is read from the current entity of the entity manager. It is allowed that the current entity is open or closed.

The entry point to the parsing rules can be specified as follows:

  • `Entry_document: This entry point corresponds to the grammar production for documents. The first generated event is always E_start_doc, it contains the whole DTD as object (no events are generated during DTD parsing, only the wholly parsed DTD is passed back). The events for the XML body follow, terminated by E_end_doc and then E_end_of_stream.
  • `Entry_content: This entry point corresponds to the grammar production for external entities (XML declaration followed by any sequence of content). The emitted events are terminated by E_end_of_stream.
  • `Entry_element_content: There is no corresponding grammar production in the XML standard. An XML declaration, followed by misc* element misc*. The emitted events are terminated by E_end_of_stream.
  • `Entry_declarations: Currently not supported. (But see Pxp_dtd_parser for functions parsing DTDs.)
  • `Entry_expr: Do not pass this entry point! There is the specially crafted function Pxp_ev_parser.process_expr for it.
The entry points have options, see Pxp_types.entry for explanations.

It may happen that several adjacent E_char_data events are emitted for the same character data section.

There are filter functions that apply normalization routines to the events, see below.

Only the following config options have an effect:

  • warner
  • encoding
  • enable_pinstr_nodes
  • enable_comment_nodes
  • enable_super_root_node
  • store_element_positions
  • name_pool and all name pool options
  • enable_namespace_processing
If an error happens, the callback function is invoked exactly once with the E_error event. The error is additionally passed to the caller by letting the exception fall through to the caller. It is not possible to resume parsing after an error.

The idea behind this special error handling is that the callback function should always be notified when the parser stops, no matter whether it is successful or not. So the last event passed to the callback function is either E_end_of_stream or E_error. You can imagine that process_entity follows this scheme:

 try
   "parse";
   eh E_end_of_stream           (* eh is the callback function *)
 with
   error ->
     "cleanup";
     let pos = ... in
     let e = At(pos, error) in
     eh (E_error e); 
     raise e
 

Note that there is always an At(_,_) exception that wraps the exception that originally occurred. - This style of exception handling applies to exceptions generated by the parser as well as to exceptions raised by the callback function.

val process_expr : ?first_token:Pxp_lexer_types.token ->
?following_token:Pxp_lexer_types.token Pervasives.ref ->
Pxp_types.config ->
Pxp_entity_manager.entity_manager -> (Pxp_types.event -> unit) -> unit
This is a special parsing function that corresponds to the entry `Entry_expr, i.e. it parses a single element, processing instruction, or comment. In contrast to process_entity, the current entity is not opened, but it is expected that the entity is already open. Of course, the entity is not closed after parsing (except an error happens).

  • first_token: This token is prepended to the tokens read from the entity manager.
  • following_token: The token following the last parsed token is optionally stored into this variable. Note: By design the parser always reads the following token. I know that this may lead to serious problems when it is tried to integrate this parser with another parser. It is currently hard to change!

val close_entities : Pxp_entity_manager.entity_manager -> unit
Closes all entities managed by this entity manager, and frees operating system resources like open files.
val create_pull_parser : Pxp_types.config ->
Pxp_types.entry ->
Pxp_entity_manager.entity_manager -> unit -> Pxp_types.event option
Invoke the event parser using the pull model. It is used as:
 let next_event = create_pull_parser cfg entry mng in
 let ev = next_event()
 

Now next_event should be invoked repeatedly until it returns None, indicating the end of the document. The events are encoded as Some ev.

The function returns exactly the same events as process_entity.

In contrast to process_entity, no exception is raised when an error happens. Only the E_error event is generated (as last event before None).

To create a stream of events, just do:

 let next = create_pull_parser cfg entry mng in
 let stream = Stream.from(fun _ -> next())
 

pxp-1.2.9/doc/manual/html/ref/type_Pxp_ev_parser.html0000644000175000017500000001126013055274551021273 0ustar gerdgerd PXP Reference : Pxp_ev_parser sig
  val create_entity_manager :
    ?is_document:bool ->
    Pxp_types.config -> Pxp_types.source -> Pxp_entity_manager.entity_manager
  val process_entity :
    Pxp_types.config ->
    Pxp_types.entry ->
    Pxp_entity_manager.entity_manager -> (Pxp_types.event -> unit) -> unit
  val process_expr :
    ?first_token:Pxp_lexer_types.token ->
    ?following_token:Pxp_lexer_types.token Pervasives.ref ->
    Pxp_types.config ->
    Pxp_entity_manager.entity_manager -> (Pxp_types.event -> unit) -> unit
  val close_entities : Pxp_entity_manager.entity_manager -> unit
  val create_pull_parser :
    Pxp_types.config ->
    Pxp_types.entry ->
    Pxp_entity_manager.entity_manager -> unit -> Pxp_types.event option
end
pxp-1.2.9/doc/manual/html/ref/Pxp_event.html0000644000175000017500000004254013055274551017372 0ustar gerdgerd PXP Reference : Pxp_event

Module Pxp_event

module Pxp_event: sig .. end
Dealing with events (for pull parsing)


Dealing with events (for pull parsing)

Events as lists


val to_list : (unit -> Pxp_types.event option) -> Pxp_types.event list
Fetch all events from the pull function, and return the corresponding list of events.
val of_list : Pxp_types.event list -> unit -> Pxp_types.event option
of_list l: Create a pull function fetching the events from l
val concat : (unit -> Pxp_types.event option) list -> unit -> Pxp_types.event option
let p = concat l: The pull functions contained in the list l are concatenated, and a new pull function p is created that pulls from the functions of the list in turn (when one function indicates the end of the events, it is continued with the next function in the list).
val iter : (Pxp_types.event -> unit) -> (unit -> Pxp_types.event option) -> unit
iter f p: The pull function p is repeatedly called to get a stream of events e. For each event the function f is called.
val extract : Pxp_types.event ->
(unit -> Pxp_types.event option) -> unit -> Pxp_types.event option
let next' = extract e next: Extracts a subexpression from the pull function next prepended by e. A subexpression consists of either
  • a single data, comment, PI, or error event
  • a start tag, either of an element, a super root, or a document, until the corresponding end tag
  • a position event followed by a subexpression
The returned pull function contains all events of the subexpression. When the extracted stream is read, the original stream is read, too.

Example:

 let l = [ E_pinstrE_start_tagE_dataE_start_tagE_end_tag;
           E_commentE_end_tagE_data ];;
 let g = of_list l;;
 g();;
 let Some e = g();;         (* e = E_start_tag *)
 let g' = extract e g;;
 g'();;                     (* returns Some E_start_tag *)
 ...
 g'();;                     (* returns Some E_end_tag *)
 g'();;                     (* returns None, end of subexpression *)
 g();;                      (* returns Some E_data *)
 g();;                      (* returns None *)
 


Filters


type pull_fn = unit -> Pxp_types.event option 
type filter = pull_fn -> pull_fn 
A filter transforms a pull function into another pull function
val norm_cdata_filter : filter
This filter
  • removes empty E_char_data events
  • concatenates adjacent E_char_data events
but does not touch any other parts of the event stream.
val drop_ignorable_whitespace_filter : filter
This filter
  • checks whether character data between elements in a "regexp" or "non-PCDATA mixed" content model consists only of whitespace, and
  • removes these whitespace characters from the event stream.
If the check fails, a WF_Error will be raised.

This filter works only if the DTD found in the event stream actually contains element declarations. This is usually enabled by including the `Extend_dtd_fully or `Val_mode_dtd options to the entry passed to the create_pull_parser call. Furthermore, there must be an E_start_doc event.

This filter does not perform any other validation checks.

val pfilter : (Pxp_types.event -> bool) -> filter
Filters an event stream by a predicate

Example: Remove comments:

 pfilter (function E_comment _ -> false | _ -> true) g 

val unwrap_document : pull_fn -> (unit -> string * Pxp_dtd.dtd) * pull_fn
This filter removes the document wrapping from the stream (see The wrapping for closed documents for a definition what this is). It is called like

         let (get_doc_details, next') = unwrap_document next
         let (version, dtd) = get_doc_details()
       

The returned filter removes any E_start_doc, E_end_doc, E_start_super, E_end_super, and E_end_of_stream events. If an E_error event is encountered, the contained exception is raised. All other events of the stream remain.

The function get_doc_details can be called to get details about the document definition. If an E_start_doc event is found in the stream, the XML version string and the DTD object are returned. The function fails if E_start_doc is not the first event of the stream.


Helpers for namespace processing



The names in E_start_tag can be analyzed with the following.
val namespace_split : string -> string * string
let (p,l) = namespace_split name: Splits name into the prefix p and the local name l. If there is no colon in name, the function returns p="", and l=name.
val extract_prefix : string -> string
Returns the prefix in the name, or "" if there is no prefix. Same as fst(namespace_split name).

Printing event streams


type dtd_style = [ `Ignore | `Include | `Reference ] 
val write_events : ?default:string ->
?dtd_style:dtd_style ->
?minimization:[ `AllEmpty | `None ] ->
Pxp_types.output_stream ->
Pxp_types.encoding ->
Pxp_types.rep_encoding -> (unit -> Pxp_types.event option) -> unit
Writes the events to the output_stream. The events must be encoded as indicated by the rep_encoding argument, but the output is written as specified by the encoding argument.

The normalized namespace prefixes are declared as needed. Additionally, one can set the default namespace by passing default, which must be the normalized prefix of the default namespace.

For E_doc_start events, the DTD may be written. This is controlled by dtd_style:

  • `Ignore: No DOCTYPE clause is written
  • `Include: The DOCTYPE clause is written, and the DTD is included in the internal subset (the default)
  • `Reference: The DOCTYPE clause is written as a reference to an external DTD
Option minimization: How to write out empty elements. `AllEmpty means that all empty elements are minimized (using the <name/> form). `None does not minimize at all and is the default.
val display_events : ?dtd_style:dtd_style ->
?minimization:[ `AllEmpty | `None ] ->
Pxp_types.output_stream ->
Pxp_types.encoding ->
Pxp_types.rep_encoding -> (unit -> Pxp_types.event option) -> unit
Writes the events to the output_stream. The events must be encoded as indicated by the rep_encoding argument, but the output is written as specified by the encoding argument.

Namespace prefixes are declared as defined in the namespace scopes. Missing prefixes are invented on the fly.

The way the DTD is printed can be set as in write_events.

val string_of_event : Pxp_types.event -> string
Returns a string representation of events, for debugging
pxp-1.2.9/doc/manual/html/ref/type_Pxp_event.html0000644000175000017500000002040113055274551020423 0ustar gerdgerd PXP Reference : Pxp_event sig
  val to_list : (unit -> Pxp_types.event option) -> Pxp_types.event list
  val of_list : Pxp_types.event list -> unit -> Pxp_types.event option
  val concat :
    (unit -> Pxp_types.event option) list -> unit -> Pxp_types.event option
  val iter :
    (Pxp_types.event -> unit) -> (unit -> Pxp_types.event option) -> unit
  val extract :
    Pxp_types.event ->
    (unit -> Pxp_types.event option) -> unit -> Pxp_types.event option
  type pull_fn = unit -> Pxp_types.event option
  type filter = Pxp_event.pull_fn -> Pxp_event.pull_fn
  val norm_cdata_filter : Pxp_event.filter
  val drop_ignorable_whitespace_filter : Pxp_event.filter
  val pfilter : (Pxp_types.event -> bool) -> Pxp_event.filter
  val unwrap_document :
    Pxp_event.pull_fn -> (unit -> string * Pxp_dtd.dtd) * Pxp_event.pull_fn
  val namespace_split : string -> string * string
  val extract_prefix : string -> string
  type dtd_style = [ `Ignore | `Include | `Reference ]
  val write_events :
    ?default:string ->
    ?dtd_style:Pxp_event.dtd_style ->
    ?minimization:[ `AllEmpty | `None ] ->
    Pxp_types.output_stream ->
    Pxp_types.encoding ->
    Pxp_types.rep_encoding -> (unit -> Pxp_types.event option) -> unit
  val display_events :
    ?dtd_style:Pxp_event.dtd_style ->
    ?minimization:[ `AllEmpty | `None ] ->
    Pxp_types.output_stream ->
    Pxp_types.encoding ->
    Pxp_types.rep_encoding -> (unit -> Pxp_types.event option) -> unit
  val string_of_event : Pxp_types.event -> string
end
pxp-1.2.9/doc/manual/html/ref/Pxp_dtd_parser.html0000644000175000017500000001011313055274551020367 0ustar gerdgerd PXP Reference : Pxp_dtd_parser

Module Pxp_dtd_parser

module Pxp_dtd_parser: sig .. end
Calling the parser to read DTDs

val create_empty_dtd : Pxp_types.config -> Pxp_dtd.dtd
Create an empty DTD. See also Pxp_dtd.create_dtd for a lower-level DTD constructor not requiring a full config record.
val parse_dtd_entity : Pxp_types.config -> Pxp_types.source -> Pxp_dtd.dtd
Parse an entity containing a DTD (external subset), and return this DTD.
val extract_dtd_from_document_entity : Pxp_types.config -> Pxp_types.source -> Pxp_dtd.dtd
Parses a closed document, i.e. a document beginning with <!DOCTYPE...>, and returns the DTD contained in the document. The parts of the document outside the DTD are actually not parsed, i.e. parsing stops when all declarations of the DTD have been read.
pxp-1.2.9/doc/manual/html/ref/type_Pxp_dtd_parser.html0000644000175000017500000000566313055274551021446 0ustar gerdgerd PXP Reference : Pxp_dtd_parser sig
  val create_empty_dtd : Pxp_types.config -> Pxp_dtd.dtd
  val parse_dtd_entity : Pxp_types.config -> Pxp_types.source -> Pxp_dtd.dtd
  val extract_dtd_from_document_entity :
    Pxp_types.config -> Pxp_types.source -> Pxp_dtd.dtd
end
pxp-1.2.9/doc/manual/html/ref/Pxp_codewriter.html0000644000175000017500000001242113055274551020413 0ustar gerdgerd PXP Reference : Pxp_codewriter

Module Pxp_codewriter

module Pxp_codewriter: sig .. end
Generate O'Caml code for creating large constant XML trees


See also Pxp_marshal for direct marshalling functions.
val write_document : Pervasives.out_channel ->
(< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a)
Pxp_document.document -> unit
Writes O'Caml code to the out_channel so that when the code is compiled and executed, a fresh document is created with the same contents as the passed document:

 "let create_document ?enable_namespace_processing config spec = ...;;" 

If you compile the code and call create_document config spec the function creates a document tree which is (almost) equal to the passed document.

The following properties may not be equal:

  • Parsed entities
  • Whether a declaration occurs in an external entity or not
  • config: The configuration to assume for re-creating the tree
  • spec: a Pxp_document.spec
  • enable_namespace_processing: You can pass here a namespace_manager to enable the namespace code (default: no namespace processing)

val write_subtree : Pervasives.out_channel ->
(< clone : 'a; node : 'a Pxp_document.node;
set_node : 'a Pxp_document.node -> unit; .. >
as 'a)
Pxp_document.node -> unit
Writes O'Caml code to the out_channel so that when the code is compiled and executed, a fresh tree is created with the same contents as the passed tree:

 "let create_subtree dtd spec = ...;;" 

If you compile the code and call create_subtree dtd spec the function creates a DTD object which is equal to the passed object.

  • dtd: a DTD object
  • spec: a Pxp_document.spec

pxp-1.2.9/doc/manual/html/ref/type_Pxp_codewriter.html0000644000175000017500000000741413055274551021462 0ustar gerdgerd PXP Reference : Pxp_codewriter sig
  val write_document :
    Pervasives.out_channel ->
    (< clone : 'a; node : 'Pxp_document.node;
       set_node : 'Pxp_document.node -> unit; .. >
     as 'a)
    Pxp_document.document -> unit
  val write_subtree :
    Pervasives.out_channel ->
    (< clone : 'a; node : 'Pxp_document.node;
       set_node : 'Pxp_document.node -> unit; .. >
     as 'a)
    Pxp_document.node -> unit
end
pxp-1.2.9/doc/manual/html/ref/Intro_trees.html0000644000175000017500000011644113055274551017721 0ustar gerdgerd PXP Reference : Intro_trees

Intro_trees


Editorial note: The PXP tree API has some complexity. The definition in Pxp_document is hard to read without some background information. This introduction is supposed to provide this information.

Also note that there is also a stream representation of XML. See Intro_events for more about this.

The structure of document trees

In a document parsed with the default parser settings every node represents either an element or a character data section. There are two classes implementing the two aspects of nodes: Pxp_document.element_impl, and Pxp_document.data_impl. There are configurations which allow more node types to be created, in particular processing instruction nodes, comment nodes, and super root nodes, but these are discussed later. Note that you can always add these extra node types yourself to the node tree no matter what the parser configuration specifies.

The following figure shows an example how a tree is constructed from element and data nodes. The circular areas represent element nodes whereas the ovals denote data nodes. Only elements may have subnodes; data nodes are always leaves of the tree. The subnodes of an element can be either element or data nodes; in both cases the O'Caml objects storing the nodes have the class type Pxp_document.node.

A tree with element nodes, data nodes, and attributes

Attributes (the clouds in the picture) do not appear as nodes of the tree, and one must use special access methods to get them.

You would get such a tree by parsing with

  let config = Pxp_types.default_config
  let source = Pxp_types.from_string 
                  "An orangeCherries"
  let spec = Pxp_tree_parser.default_spec
  let doc = Pxp_tree_parser.parse_document_entity config source spec
  let root = doc#root

The config record sets a lot of parsing options. A number of these options are explained below. The source argument says from where the parsed text comes. For the mysterious spec parameter see below.

The parser returns doc, which is a Pxp_document.document. You have to call its root method to get the root of the tree. Note that there are other parsing functions that return directly nodes; these are intended for parsing XML fragments, however. For the usual closed XML documents use a function that returns a document.

The root is, as other nodes of the tree, an object instance of the Pxp_document.node class type.

What about other things that can occur in XML text? As mentioned, by default only elements and data nodes appear in the tree, but it is possible to enable more node types by setting appropriate Pxp_types.config options:

  • Comments are ignored by default. By setting the config option enable_comment_nodes, however, comments are added to the tree. There is a special node type for comments.
  • Processing instructions (denoted by <? ... ?> parentheses) are not ignored, but normally no nodes are created for them. The instructions are only gathered up, and attached to the surrounding node, so one can check for their presence but not for their exact location. By setting the config option enable_pinstr_nodes, however, processing instructions are added to the tree as normal nodes. There is also a special node type for them.
  • Usually, the topmost element is the root of the tree. There is, however, the difficulty that the XML syntax allows one to surround the topmost element by comments and processing instructions. For an exact representation of this, it is possible to put an artificial root node at the top of the tree, so that the topmost element is one of the children, and the other surrounding material appears as the other children. This mode is enabled by setting enable_super_root_node. The node is called super root node, and is also a special type of node.
  • It is possible to also get attributes and even namespaces as node objects, but they are never put into the regular tree. To get these very special nodes, one has to use special access methods.
  • CDATA sections (like <![CDATA[some text]]>) are simply added to the surrounding data node, so they do not appear as nodes of their own.
  • Entity references (like &amp;) are automatically resolved, and the resolution is added to the surrounding node
The parser collapses as much data material into one data node as possible such that there are normally never two adjacent data nodes. This invariant is enforced even if data material is included by entity references or CDATA sections, or if a data sequence is interrupted by comments. So

 a &amp; b <!-- comment --> c <![CDATA[<> d]]> 

is represented by only one data node, for instance (for the default case where no comment nodes are created). Of course, you can create document trees manually which break this invariant; it is only the way the parser forms the tree.

All types of nodes are represented by the same Ocaml objects of class type Pxp_document.node. The method Pxp_document.node.node_type returns a hint which type of node the object is. See the type Pxp_document.node_type for details how the mentioned node types are reflected by this method. For instance, for elements this method returns T_element n where n is the name of the element.

Note that this means formally that all access methods are implemented for all node types. For example, you can get the attributes of data nodes by calling the Pxp_document.node.attributes method, although this does not make sense. This problem is resolved on a case-by-case basis by either returning an "empty value" or by raising appropriate exceptions (e.g. Pxp_core_types.S.Method_not_applicable). For the chosen typing it is not possible to define slimmer class types that better fit the various node types.

Attributes are usually represented as pairs string * att_value of names and values. Here, Pxp_core_types.S.att_value is a conventional variant type. There are lots of access methods for attributes, see below. It is optionally possible to wrap the attributes as nodes (method Pxp_document.node.attributes_as_nodes), but even in this case the attributes are outside the regular document tree.

Normally, the processing instructions are also not included into the document tree. They are considered as an extra property of the element to which they are attached, and can be retrieved by the Pxp_document.node.pinstr method of the element node. If this way of handling processing instructions is not exact enough, the parser can optionally create processing instruction nodes that are regular members of the document tree.

Access methods

An overview over some relevant access methods:

  • General:
    • dtd (Pxp_document.node.dtd): returns the DTD object. All nodes have such an object, even in well-formed mode.
    • encoding (Pxp_document.node.encoding): returns the encoding of the in-memory document representation.
  • Navigation:
    • parent (Pxp_document.node.parent): returns the parent object of the node it is called on
    • root (Pxp_document.node.root): returns the root of the tree the node is member of
    • sub_nodes (Pxp_document.node.sub_nodes): returns the children of the node
    • previous_node (Pxp_document.node.previous_node): returns the left sibling
    • next_node (Pxp_document.node.next_node): returns the right sibling
  • Information:
    • node_position (Pxp_document.node.node_position): returns the ordinal position of this node as child of the parent
    • node_path (Pxp_document.node.node_path): returns the positional path of this node in the whole tree
    • node_type (Pxp_document.node.node_type): returns the type of the node
    • position (Pxp_document.node.position): returns the position of the node in the parsed XML text
  • Content:
    • data (Pxp_document.node.data): returns the data contents of data nodes
    • attributes (Pxp_document.node.attributes): returns the attributes of elements
    • attributes_as_nodes (Pxp_document.node.attributes_as_nodes): also returns the attributes, but represented as a list of nodes residing outside the tree
    • comment (Pxp_document.node.comment): returns the text of the XML comment
  • Validation:
    • validate (Pxp_document.node.validate): validates the element locally
  • Namespace: (Only if namespaces are enabled, and the namespace-aware node implementation is used)
    • localname (Pxp_document.node.localname): returns the local name of the element in the namespace
    • namespace_uri (Pxp_document.node.namespace_uri): returns the namespace URI of the node
    • namespace_scope (Pxp_document.node.namespace_scope): returns the scope object with more namespace query methods
    • namespaces_as_nodes (Pxp_document.node.namespaces_as_nodes): returns the namespaces this node is member of, and the namespaces are represented as list of nodes

Mutation methods

Trees are mutable, and nodes are mutable. Note that the tree is not automatically (re-)validated when it is changed. You have to explicitly call validation methods, or the Pxp_document.validate function for the whole tree.

  • Building trees, changing the structure of trees:
    • append_node (Pxp_document.node.append_node): appends a node as new child to this node
    • remove (Pxp_document.node.remove): removes this node from the tree
  • Changing the content of nodes:
    • set_data (Pxp_document.node.set_data): changes the contents of data nodes
    • set_attribute (Pxp_document.node.set_attribute): adds or changes an attribute
    • set_comment (Pxp_document.node.set_comment): changes the contents of comment nodes
  • Creating nodes:
    • create_element (Pxp_document.node.create_element): called on an element node, this method creates a new tree only consisting of an element, and the only node of the tree is an object of the same class as this node
    • create_data (Pxp_document.node.create_data): same for data nodes
    • orphaned_clone (Pxp_document.node.orphaned_clone): creates a copy of the subtree starting at this node

Links between nodes

The node tree has links in both directions: Every node has a link to its parent (if any), and it has links to the subnodes (see the following picture). Obviously, this doubly-linked structure simplifies the navigation in the tree; but has also some consequences for the possible operations on trees.

Nodes are doubly linked trees

(Definitions: Pxp_document.node.parent, Pxp_document.node.sub_nodes.)

Because every node must have at most one parent node, operations are illegal if they violate this condition. The following figure shows on the left side that node y is added to x as new subnode which is allowed because y does not have a parent yet. The right side of the picture illustrates what would happen if y had a parent node; this is illegal because y would have two parents after the operation.

A node can only be added if it is a root

(Definition: Pxp_document.node.append_node.)

The remove operation simply removes the links between two nodes. In the following picture the node x is deleted from the list of subnodes of y. After that, x becomes the root of the subtree starting at this node.

A removed node becomes the root of the subtree

(Definition: Pxp_document.node.remove.)

It is also possible to make a clone of a subtree; illustrated in the next picture. In this case, the clone is a copy of the original subtree except that it is no longer a subnode. Because cloning never keeps the connection to the parent, the clones are called orphaned.

The clone of a subtree

(Definition: Pxp_document.node.orphaned_clone.)

Optional features of document trees

As already pointed out, the parser does only create element and data nodes by default. The configuration of the parser can be controlled by the Pxp_types.config record. There are a number of optional features that change the way the document trees are constructed by the parser:

Note that the parser configuration only controls the parser. If you create trees of your own, you can simply add all the additional node types to the tree without needing to enable these features.

  • When enable_super_root_node is set, the extra super root node is generated at the top of the tree. This node has type T_super_root.
  • The option enable_comment_nodes lets the parser add comment nodes when it parses comments. These nodes have type T_comment.
  • The option enable_pinstr_nodes changes the way processing instructions are added to the document. Instead of attaching such instructions to their containing elements as additional properties, this mode forces the parser to create real nodes of type T_pinstr for them.
  • The option drop_ignorable_whitespace (enabled by default) can be turned off. It controls whether the parser skips over so-called ignorable whitespace. The XML standard allows that elements contain whitespace characters even if they are declared in the DTD not to contain character data. Because of this, the parser considers such whitespace as ignorable detail of the XML instance, and drops the characters silently. You can change this by setting drop_ignorable_whitespace to false. In this case, every character of the XML instance will be accepted by the parser and will be added to a data node of the document tree.
  • By default, the parser creates elements with an annotation about the location in the XML source file. You can query this location by calling the method position. As this requires a lot of memory, it is possible to turn this off by setting store_element_positions to false.

There are a number of further configuration options; however, these options do not change the structure of the document tree.

Optional features of nodes

The following features exist per node, and are simply invoked by using the methods dealing with them.

  • Attribute nodes: These are useful if you want to have data structures that contain attributes together with other types of nodes. The method attributes_as_nodes returns the attributes wrapped into node objects. Note that these nodes are read-only.
  • Validation: The document nodes contain the routines validating the document body. Of course, the validation checks depend on what is stored in the DTD object. (There is always a DTD object - even in well-formedness mode, only that it is mostly empty then, and validation is a no-op.)

    The DTD object contains the declarations of elements, attribute lists, entities, and notations. Furthermore, the DTD knows whether the document is flagged as "standalone". As a PXP extension to classic XML processing, the DTD may specify a mixed mode between "validating mode" and "well-formedness mode". It is possible to allow non-declared elements in the document, but to check declared elements against their declaration at the same time. Moreover, there is a similar feature for attribute lists; you can allow non-declared attributes and check declared attributes. (Well, the whole truth is that the parser always works in this mix mode, and that the "validating mode" and the "well-formedness mode" are only the extremes of the mix mode.)

Creating nodes and trees

Often, the parser creates the trees, but on occasion it is useful to create trees manually. We explain here only the basic mechanism. There is a nice camlp4 syntax extension called pxp-pp (XXX: LINK) allowing for a much better notation in programs.

The most basic way of creating new nodes are the create_element, create_data, and create_other methods of nodes. It is not recommended to use them directly, however, as they are very primitive.

In the Pxp_document module there are a number of functions creating individual nodes (without children), the node constructors:

  • Pxp_document.create_element_node: creates an element node
  • Pxp_document.create_data_node: creates a data node
  • Pxp_document.create_comment_node: creates a comment node
  • Pxp_document.create_pinstr_node: creates a processing instruction node
  • Pxp_document.create_super_root_node: creates a super root node
There are no functions to create attribute and namespace nodes - these are always created automatically by their containing nodes, so the user does not need to do anything for creating them.

The node constructors must be equipped with all required data to create the requested type of node. This includes the data that would have been available in the textual XML representation, and some of the meta data passed to the parsers, and meta data implicitly generated by the parsers. For an element, this is at minimum:

  • The name of the element (e.g. the "foo" in <foo>)
  • The attributes of the element
  • The DTD object to use (a rudimentary DTD object is even required if only well-formedness checks will be applied but no validation)
  • The specification which classes are instantiated to create the nodes
For the latter two, see below. Optionally one can provide:

  • The position of the element in the XML text
  • Whether the attribute list is to be validated at creation time
  • Whether name pools are to be used for the attributes
Regarding validation, the default is to validate local data such as attributes, but to omit any checks of the position the node has in the tree. The tree is still a singleton, and consists only of one node after creation, so non-local checks do not make sense.

After some nodes have been created, they can be combined to more complex trees by mutation methods (e.g. Pxp_document.node.append_node).

As mentioned, a node must always be connected with a DTD object, even if no validation checks will be done. It is possible to create DTD objects that do not impose restrictions on the document:

 
  let dtd = Pxp_dtd_parser.create_empty_dtd config
  dtd # allow_arbitrary

Even such a DTD object can contain entity definitions, and can demand a certain way of dealing with namespaces. Also, the character encoding of the nodes is taken from the DTD. See Pxp_dtd.dtd for DTD methods, and Pxp_dtd_parser for convenient ways to create DTD objects. Note that all nodes of a tree must be connected to the same DTD object.

PXP is not restricted to using built-in classes for nodes. When the parser is invoked and a tree is built, it is looked up in a so-called document model specification how the new objects have to be created (type Pxp_document.spec. Basically, it is a list of sample objects to use (which are called exemplars), and these objects are cloned when a node is actually created.

When calling the node constructors directly (bypassing the parser), the document model specification has also to be passed to them as argument. It is used in the same way as the parser uses it.

For getting the built-in classes without any modification, just use Pxp_tree_parser.default_spec. For the variant with enabled namespaces, prefer Pxp_tree_parser.default_namespace_spec.

Extended nodes

Every node in a tree has a so-called extension. By default, the extension is practically empty and only present for formal uniformity. However, one can also define custom extension classes, and effectively add new methods to the node classes.

Node extensions are explained in detail here: Intro_extensions

Namespaces

As an option, PXP processes namespace declarations in XML text. See this separate introduction for details: Intro_namespaces.

Details of the mapping from XML text to the tree representation

If an element declaration does not allow the element to contain character data, the following rules apply.

If the element must be empty, i.e. it is declared with the keyword EMPTY, the element instance must be effectively empty (it must not even contain whitespace characters). The parser guarantees that a declared EMPTY element never contains a data node, even if the data node represents the empty string.

If the element declaration only permits other elements to occur within that element but not character data, it is still possible to insert whitespace characters between the subelements. The parser ignores these characters, too, and does not create data nodes for them.

Example. Consider the following element types:

<!ELEMENT x ( #PCDATA | z )* >
<!ELEMENT y ( z )* >
<!ELEMENT z EMPTY>

Only x may contain character data, the keyword #PCDATA indicates this. The other types are character-free.

The XML term

<x><z/> <z/></x>

will be internally represented by an element node for x with three subnodes: the first z element, a data node containing the space character, and the second z element. In contrast to this, the term

<y><z/> <z/></y>

is represented by an element node for y with only two subnodes, the two z elements. There is no data node for the space character because spaces are ignored in the character-free element y.

Parser option: By setting the parser option drop_ignorable_whitespace to false, the behaviour of the parser is changed such that even ignorable whitespace characters are represented by data nodes.

The representation of character data

The XML specification allows all Unicode characters in XML texts. This parser can be configured such that UTF-8 is used to represent the characters internally; however, the default character encoding is ISO-8859-1. (Currently, no other encodings are possible for the internal string representation; the type Pxp_core_types.S.rep_encoding enumerates the possible encodings. Principally, the parser could use any encoding that is ASCII-compatible, but there are currently only lexical analyzers for UTF-8 and ISO-8859-1. It is currently impossible to use UTF-16 or UCS-4 as internal encodings (or other multibyte encodings which are not ASCII-compatible) unless major parts of the parser are rewritten - unlikely...)

The internal encoding may be different from the external encoding (specified in the XML declaration <?xml ... encoding="..."?>); in this case the strings are automatically converted to the internal encoding.

If the internal encoding is ISO-8859-1, it is possible that there are characters that cannot be represented. In this case, the parser ignores such characters and prints a warning (to the collect_warning object that must be passed when the parser is called).

The XML specification allows lines to be separated by single LF characters, by CR LF character sequences, or by single CR characters. Internally, these separators are always converted to single LF characters.

The parser guarantees that there are never two adjacent data nodes; if necessary, data material that would otherwise be represented by several nodes is collapsed into one node. Note that you can still create node trees with adjacent data nodes; however, the parser does not return such trees.

Note that CDATA sections are not represented specially; such sections are added to the current data material that is being collected for the next data node.

The representation of entities within documents

Entities are not represented within documents! If the parser finds an entity reference in the document content, the reference is immediately expanded, and the parser reads the expansion text instead of the reference.

The representation of attributes

As attribute values are composed of Unicode characters, too, the same problems with the character encoding arise as for character material. Attribute values are converted to the internal encoding, too; and if there are characters that cannot be represented, these are dropped, and a warning is printed.

Attribute values are normalized before they are returned by methods like attribute. First, any remaining entity references are expanded; if necessary, expansion is performed recursively. Second, newline characters (any of LF, CR LF, or CR characters) are converted to single space characters. Note that especially the latter action is prescribed by the XML standard (but &#10; is not converted such that it is still possible to include line feeds into attributes).

The representation of processing instructions

Processing instructions are parsed to some extent: The first word of the PI is called the target, and it is stored separated from the rest of the PI:

<?target rest?>

The exact location where a PI occurs is not represented (by default). The parser attaches the PI to the object that represents the embracing construct (an element, a DTD, or the whole document); that means you can find out which PIs occur in a certain element, in the DTD, or in the whole document, but you cannot lookup the exact position within the construct.

Parser option: If you require the exact location of PIs, it is possible to create regular nodes for them instead of attaching them to the surrounding node as property. This mode is controlled by the option enable_pinstr_nodes. The additional nodes have the node type T_pinstr target, and are created from special exemplars contained in the spec (see Pxp_document.spec).

The representation of comments

Normally, comments are not represented; they are dropped by default.

Parser option: However, if you require comment in the document tree, it is possible to create T_comment nodes for them. This mode can be specified by the option enable_comment_nodes. Comment nodes are created from special exemplars contained in the spec (see Pxp_document.spec). You can access the contents of comments through the method comment.

The attributes xml:lang and xml:space

These attributes are not supported specially; they are handled like any other attribute.

Note that the utility function Pxp_document.strip_whitespace respects xml:space
pxp-1.2.9/doc/manual/html/ref/type_Intro_trees.html0000644000175000017500000000404113055274551020752 0ustar gerdgerd PXP Reference : Intro_trees sig  endpxp-1.2.9/doc/manual/html/ref/Intro_extensions.html0000644000175000017500000004074713055274551021003 0ustar gerdgerd PXP Reference : Intro_extensions

Intro_extensions


This text explains the custom node extensions that can be attached to XML trees. This feature can be ignored by users that do not need it. We effectively comment the class type Pxp_document.extension here.

Node extensions

Every node in a tree has a so-called extension. By default, the extension is practically empty and only present for formal uniformity. However, one can also define custom extension classes, and effectively make new methods available to nodes.

The type Pxp_document.extension is:

class type [ 'node ] extension =
  object ('self)
    method clone : 'self
    method node : 'node
    method set_node : 'node -> unit
  end

Every node has such an extension object, as the following picture shows. Of course, the idea is to equip the extension object with additional methods and not only clone, node, and set_node - which are simply the bare minimum.

Node objects and extension objects

The picture shows how the nodes and extensions are linked together. Every node has a reference to its extension, and every extension has a reference to its node. The methods extension and node follow these references; a typical phrase is

 self # node # attribute "xy" 

to get the value of an attribute from a method defined in the extension object; or

self # node # iter
  (fun n -> n # extension # my_method ...)

to iterate over the subnodes and to call my_method of the corresponding extension objects.

Note that extension objects do not have references to subnodes (or "subextensions") themselves; in order to get one of the children of an extension you must first go to the node object, then get the child node, and finally reach the extension that is logically the child of the extension you started with.

In other programming languages, it is possible to extend the node objects directly. Ocaml's subtyping rules make this practically impossible. The type of the extension object appears as type parameter in the class type of the nodes. Note that this means that the type of the extension objects has to be the same for all nodes in a tree. It is not possible to e.g. use a different type for elements than for data nodes.

How to define an extension class

At minimum, you must define the methods clone, node, and set_node such that your class is compatible with the type Pxp_document.extension. The method set_node is called during the initialization of the node, or after a node has been cloned; the node object invokes set_node on the extension object to tell it that this node is now the object the extension is linked to. The extension must return the node object passed as argument of set_node when the node method is called.

The clone method must return a copy of the extension object; at least the object itself must be duplicated, but if required, the copy should deeply duplicate all objects and values that are referred by the extension, too. Whether this is required, depends on the application; clone is invoked by the node object when one of its cloning methods is called.

A good starting point for an extension class:

class custom_extension =
  object (self)

    val mutable node = (None : custom_extension node option)

    method clone = {< >} 

    method node =
      match node with
          None ->
            assert false
        | Some n -> n

    method set_node n =
      node <- Some n

  end

This class is compatible with Pxp_document.extension. The purpose of defining such a class is, of course, adding further methods; and you can do it without restriction.

Often, you want more than only a single extension class. In this case, it is strictly required that all your classes (that will be used in the same tree) have the same type of extensions (with respect to the interface; i.e. it does not matter if your classes differ in the defined private methods and instance variables, but public methods count). It is simple to implement:

class custom_extension =
  object (self)
    val mutable node = (None : custom_extension node option)

    method clone = ...      (* see above *)
    method node = ...       (* see above *)
    method set_node n = ... (* see above *)

    method virtual my_method1 : ...
    method virtual my_method2 : ...
    ... (* etc. *)
  end

class custom_extension_kind_A =
  object (self)
    inherit custom_extension

    method my_method1 = ...
    method my_method2 = ...
  end

class custom_extension_kind_B =
  object (self)
    inherit custom_extension

    method my_method1 = ...
    method my_method2 = ...
  end

If a class does not need a method (e.g. because it does not make sense, or it would violate some important condition), it is possible to define the method and to always raise an exception when the method is invoked (e.g. assert false).

How to bind extension classes to element types

Once you have defined your extension classes, you can bind them to element types. The simplest case is that you have only one class and that this class is always to be used. The parsing functions in the module Pxp_tree_parser take a spec argument for the document model specification which can be customized (of type Pxp_document.spec). If your single class has the name c, this argument should be

let spec =
  Pxp_document.make_spec_from_alist
    ~data_exemplar:            (new Pxp_document.data_impl c)
    ~default_element_exemplar: (new Pxp_document.element_impl c)
    ~element_alist:            []
    ()

This means that data nodes will be created from the exemplar passed by ~data_exemplar and that all element nodes will be made from the exemplar specified by ~default_element_exemplar. In ~element_alist, you can pass that different exemplars are to be used for different element types; but this is an optional feature. If you do not need it, pass the empty list.

Remember that an exemplar is a (node, extension) pair that serves as pattern when new nodes (and the corresponding extension objects) are added to the document tree. In this case, the exemplar contains c as extension, and when nodes are created, the exemplar is cloned, and cloning makes also a copy of c such that all nodes of the document tree will have a copy of c as extension.

The ~element_alist argument can bind specific element types to specific exemplars; as exemplars may be instances of different classes it is effectively possible to bind element types to classes. For example, if the element type "p" is implemented by class c_p, and "q" is realized by c_q, you can pass the following value:

let spec =
  Pxp_document.make_spec_from_alist
    ~data_exemplar:            (Pxp_document.new data_impl c)
    ~default_element_exemplar: (Pxp_document.new element_impl c)
    ~element_alist:            
      [ "p"new Pxp_document.element_impl c_p;
        "q"new Pxp_document.element_impl c_q;
      ]
    ()

The extension object c is still used for all data nodes and for all other element types.

An example

A complete example using extension objects is the readme processor. The full source code is included in the PXP source tarball. A commented version is available here: Example_readme.


pxp-1.2.9/doc/manual/html/ref/type_Intro_extensions.html0000644000175000017500000000404613055274551022034 0ustar gerdgerd PXP Reference : Intro_extensions sig  endpxp-1.2.9/doc/manual/html/ref/Intro_namespaces.html0000644000175000017500000004167713055274552020727 0ustar gerdgerd PXP Reference : Intro_namespaces

Intro_namespaces


This text explains how PXP deals with the optional namespace declarations in XML text.

Namespaces

PXP supports namespaces (but they have to be explicitly enabled). In order to simplify the handling of namespace-aware documents PXP applies a transformation to the document which is called "prefix normalization". This transformation ensures that every namespace prefix uniquely identifies a namespace throughout the whole document.

Links to other documentation

Namespace URI's and prefixes

A namespace is identified by a namespace URI (e.g. something like "http://company.org/namespaces/project1" - note that this URI is simply processed as string, and never looked up by an HTTP access). For brevity of formulation, one has to define a so-called namespace prefix for such a URI. For example:

 <x:q xmlns:x="http://company.org/namespaces/project1">...</q> 

The "xmlns:x" attribute is special, and declares that for this subtree the prefix "x" is to be used as replacement for the long URI. Here, "x:q" denotes that the element "q" in this namespace "x" is meant.

The problem is now that the URI defines the namespace, and not the prefix. In another subtree you may want to use the prefix "y" for the same namespace. This has always made it difficult to deal with namespaces in XML-processing software.

PXP, however, performs prefix normalization before it returns the tree. This means that all prefixes are changed to a norm prefix for the namespace. This can be the first prefix used for the namespace, or a prefix declared with a PXP extension, or a programmatically declared binding of the norm prefix to the namespace.

In order to use the PXP implementation of namespaces, one has to set enable_namespace_processing in the parser configuration, and to use namespace-aware node implementations. If you don't use extended node trees, this means to use Pxp_tree_parser.default_namespace_spec instead of Pxp_tree_parser.default_spec. A good starting point to enable all that:

  let nsmng = Pxp_dtd.create_namespace_manager()
  let config = 
        { Pxp_types.default_config with
             enable_namespace_processing = Some nsmng
        }
  let source = ...
  let spec = Pxp_tree_parser.default_namespace_spec
  let doc = Pxp_tree_parser.parse_document_entity config source spec
  let root = doc#root

The namespace-aware implementations of the node class type define additional namespace methods like namespace_uri (see Pxp_document.node.namespace_uri). (Although you also could direct the parser to create non-namespace-aware nodes, this does not make much sense, as you do not get these special access methods then.)

The method namespace_scope (see Pxp_document.node.namespace_scope) allows one to get more information what happened during prefix normalization. In particular, it is possible to find out the original prefix in the XML text (which is also called display prefix), before it was mapped to the normalized prefix. The namespace_scope method returns a Pxp_dtd.namespace_scope object with additional lookup methods.

Example for prefix normalization

In the following XML snippet the prefix "h" is declared as a shorthand for the XHTML namespace:

<h:html xmlns:h="http://www.w3.org/1999/xhtml"
  <h:head>
    <h:title>Virtual Library</h:title> 
  </h:head> 
  <h:body> 
    <h:p>Moved to <h:a href="http://vlib.org/">vlib.org</h:a>.</h:p> 
  </h:body> 
</h:html>

In this example, normalization changes nothing, because the prefix "h" has the same meaning thoughout the whole document. However, keep in mind that every author of XHTML documents can freely choose the prefix to use.

The XML standard gives the author of the document even the freedom to change the meaning of a prefix at any time. For example, here the prefix "x" is changed in the inner node:

<x:address xmlns:x="http://addresses.org">
  <x:name xmlns:x="http://names.org">
    Gerd Stolpmann
  </x:name>
</x:address>

In the outer node the prefix "x" is connected with the "http://addresses.org" namespace, but in the inner node it is connected with "http://names.org".

After normalization, the prefixes would look as follows:

<x:address xmlns:x="http://addresses.org">
  <x1:name xmlns:x1="http://names.org">
    Gerd Stolpmann
  </x1:name>
</x:address>

In order to avoid overridden prefixes, the prefix in the inner node was changed to "x1" (for type theorists: think of alpha conversion).

The idea of prefix normalization is to simplify how programs can match against element and attribute names. It is possible to configure the normalizer so that certain prefixes are used for certain URI's. In this example, we could direct the normalizer to use the prefixes "addr" and "nm" instead of the quite arbitrary strings "x" and "x1":

dtd # namespace_manager # add_namespace "addr" "http://addresses.org";
dtd # namespace_manager # add_namespace "nm" "http://names.org";

For this to work you need access to the dtd object before the parser actually starts it work. The parsing functions in Pxp_tree_parser have the special hook transform_dtd that is called at the right moment, and allows the program to enter such special configurations into the DTD object. The resulting program could look then like:

  let nsmng = Pxp_dtd.create_namespace_manager()
  let config = 
        { Pxp_types.default_config with
             enable_namespace_processing = Some nsmng
        }
  let source = ...
  let spec = Pxp_tree_parser.default_namespace_spec
  let transform_dtd dtd =
    dtd # namespace_manager # add_namespace "addr" "http://addresses.org";
    dtd # namespace_manager # add_namespace "nm" "http://names.org";
    dtd
  let doc = 
     Pxp_tree_parser.parse_document_entity ~transform_dtd config source spec
  let root = doc#root

Alternatively, it is also possible to put special processing instructions into the DTD:

<?pxp:dtd namespace prefix="addr" uri="http://addresses.org"?>
<?pxp:dtd namespace prefix="nm" uri="http://names.org"?>

The advantage of configuring specific normprefixes is that one can now use them directly in programs, e.g. for matching:

  match node#node_type with
    | T_element "addr:address" -> ...
    | T_element "nm:name" -> ...

Getting more details of namespaces

There are two additional objects that are relevant. First, there is a namespace manager for the whole tree. This object gathers all namespace URI's up that occur in the XML text, and decides which normprefixes are associated with them: Pxp_dtd.namespace_manager.

Second, there is the namespace scope. An XML tree may have a lot of such objects. A new scope object is created whenever new namespaces are introduced, i.e. when there are "xmlns" declarations. The scope object has a pointer to the scope object for the surrounding XML text. Scope objects are documented here: Pxp_dtd.namespace_scope.

Some examples (when n is a node):

  • To find out which normprefix is used for a namespace URI, use
     n # namespace_manager # get_normprefix uri 
  • To find out the reverse, i.e. which URI is represented by a certain normprefix, use
     n # namespace_manager # get_primary_uri prefix 
  • To find out which namespace URI is meant by a display prefix, i.e. the prefix as it occurs literally in the XML text:
     n # namespace_scope # uri_of_display_prefix prefix 

pxp-1.2.9/doc/manual/html/ref/type_Intro_namespaces.html0000644000175000017500000000404613055274552021755 0ustar gerdgerd PXP Reference : Intro_namespaces sig  endpxp-1.2.9/doc/manual/html/ref/Intro_events.html0000644000175000017500000022637113055274552020110 0ustar gerdgerd PXP Reference : Intro_events

Intro_events


XML data as stream of events

In contrast to the tree mode (see Intro_trees), the parser does not return the complete document at once in event mode, but as a sequence of so-called events. The parser makes a number of guarantees about the structure of the emitted events, especially it is ensured that they conform to the well-formedness constraints. For instance, it is ensured that start tags and end tags are properly nested. Nevertheless, it is up to the caller to process and/or aggregate the events. This leaves a lot of freedom for the caller.

The event mode is especially well-suited for processing very large documents. As PXP does not by itself represent the complete document in memory, PXP needs usually not to maintain large data structures in event mode. Of course, the caller should also try to avoid such data structures. This makes it then possible to even process arbitrarily large documents in many cases. Note, however, that not all limits are taken out of effect. For example, for checking well-formedness the parser still needs to maintain a stack of start elements whose end elements have not been seen yet. Because of this, it is not possible to parse arbitrarily deeply nested documents with constant memory. On 32 bit platforms, there is still a limit of the maximum string length of 16 MB.

Another application of event mode is the direct combination with recursive-descent parsers for postprocessing the stream of events. See below Connect PXP with a recursive-descent parser for more.

The event mode also makes it feasible to enable the special escape tokens {, }, {{, and }}. PXP can be configured such that these tokens trigger a user-defined add-on parser that reads directly from the character stream. See below Escape PXP parsing for more.

We should also mention one basic limitation of event-oriented parsing: It is fundamentally incompatible with validation, as the tree view is required to validate a document.

  • Pxp_types.event is the data type of events. Also explained below
  • Pxp_ev_parser is the module with parsing functions in event mode
  • Pxp_event is a module with helper functions for event mode, such as concatenation of event streams
  • Pxp_document.liquefy allows one to convert a tree into an event stream
  • Pxp_document.solidify allows one to convert an event stream into a tree
  • Generating events: pxp_evlist and pxp_evpull explains how to use the preprocessor to construct event streams

Compatibility

Event mode is compatible with:

  • Well-formedness parsing
  • Namespaces: Namespace processing works as outlined in Intro_namespaces, only that the user needs to interpret the namespace information contained in the events differently. See below Events and namespaces for more.
  • Reading from arbitrary sources as described in Intro_resolution
Event mode is incompatible with:

  • Validation

The structure of event streams

First we describe how well-formed XML fragments are represented in stream format, i.e. XML text that is properly nested with respect to start tags and end tags. For a real text, the parser will also emit some wrapping. It is distinguished between documents and non-document entities. A document is a formally closed text that consists of one main entity (file) and optionally a number of referenced entities. One can parse a file as document, and in this case the parser will add a wrapping suited for documents. Alternatively, one can parse an entity as a plain entity, and in this case the parser will add a wrapping suited for non-documents. Note that the XML declaration (<?xml ... ?>) for such non-document entities is slightly different, and that no DOCTYPE clause is permitted.

The structure of well-formed XML fragments

The type of events is Pxp_types.event. The events do not strictly correspond to syntactical elements of XML, but more to a logical interpretation.

The parser emits events for

  • E_char_data(text): Character data - The parser emits character data events for sequences of characters. It is unspecified how long these sequences are. This means it is up to the parser how a contiguous section of characters is split up into one or more character data events, i.e. adjacent character data events may be emitted by the parser. Also, it is not tried to suppress whitespace of any kind. For example, the XML text
     Hello world 
    might lead to the emission of
     [E_char_data "Hello "E_char_data "world"
    but also to any other split into events.

  • E_start_tag(name,atts,scope_opt,entid): Start tags of elements - Includes everything within the angle brackets, i.e. name and attribute list atts (as name/value pairs). The event also includes the namespace scope scope_opt if namespace processing is enabled (or None), and it includes a reference entid to the entity the tag occurs in. Note that the tag name and the attribute names are subject to prefix normalization if namespace processing is enabled.

  • E_end_tag(name,entid): End tags of elements - The event mentions the name, and the entity entid the tag occurs in. Both name and entid are always identical to the values attached to the corresponding start tag.

    Note that the short form of empty elements, <tag/> are emitted as a start tag followed by an end tag.

  • E_pinstr(name,value,entid): Processing instructions (PI's) - In tree mode, PI's can be represented in two ways: Either by attaching them to the surrounding elements, or by including them into the tree exactly where they occurred in the text. For symmetry, the same two ways of handling PI's are also present in the event stream representation (event streams and trees should be convertible into each other without data loss). Although there is only one event (E_pinstr), it depends on the config option enable_pinstr_nodes where this event is placed into the event stream. If the option is enabled, E_pinstr is always emitted where the PI occurs in the XML text. If it is disabled, the emission of E_pinstr may be delayed, but it is still guaranteed that this happens in the same context (surrounding element). It is not possible to turn the emission of PI events completely off. (See Filters for an example how to filter out PI events in a postprocessing step.)

  • E_comment text: Comments - If enabled (by enable_comment_nodes in Pxp_types.config), the parser emits comment events.

  • E_start_super and E_end_super: Super root nodes - If enabled (by enable_super_root_node in Pxp_types.config), the parser emits a start event for the super root node at the beginning of the stream, and an end event at the end of the stream. This is comparable to an element embracing the whole text.

  • E_position(e,l,p): Position events - If enabled (by store_element_positions in Pxp_types.config), the parser emits special position events. These events refer to the immediately following event, and say from where in the XML text the following event originates. Position events are emitted before E_start_tag, E_pinstr, and E_comment. The argument e is a textual description of the entity. l is the line. p is the byte position of the character.

As in the tree mode, entities are fully resolved, and do not appear in the parsed events. Also, syntactic elements like CDATA sections, the XML declaration, the DOCTYPE clause, and all elements only allowed in the DTD part are not represented.

Example for an event stream: The XML fragment

  <p a1="one"><q>data1</q><r>data2</r><s></s><t/></p>

could be represented as

  [ E_start_tag("p",["a1","one"],None,<entid>);
    E_start_tag("q",[],None,<entid>);
    E_char_data "data1";
    E_end_tag("q",<entid>);
    E_start_tag("r",[],None,<entid>);
    E_char_data "data2";
    E_end_tag("r",<entid>);
    E_start_tag("s",[],None,<entid>);
    E_end_tag("s",<entid>);
    E_start_tag("t",[],None,<entid>);
    E_end_tag("t",<entid>);
    E_end_tah("p",<entid>);
  ]

where <entid> is the entity ID object.

The wrapping for non-document entities

The XML specification demands that external XML entities (that are referenced from a document entity or another external entity) comply to this grammar (excerpt from the W3C definition):

extParsedEnt ::= TextDecl? content
TextDecl     ::= '<?xml' VersionInfoEncodingDecl S'?>'
content      ::= (element | CharData | Reference | CDSect | PI | Comment)*

i.e. there can be an XML declaration at the beginning (always with an encoding declaration), but the declaration is optional. It is followed by a sequence of elements, character data, processing instructions and comments (which are reflected by the events emitted by the parser), and by entity references and CDATA sections (which are already resolved by the parser).

The emitted events are now:

  • No event is emitted for the XML declaration
  • The stream consists of the events for the content production
  • Finally, there is an E_end_of_stream event.
When the parser detects an error, it stops the event stream, and emits a last E_error event instead.

The wrapping for closed documents

Closed documents have to match this grammar (excerpt from the W3C definition):

document ::= prolog element Misc*
prolog          ::= XMLDeclMisc* (doctypedecl Misc*)?
XMLDecl  ::= '<?xml' VersionInfo EncodingDeclSDDeclS'?>'

That means there can be an XML declaration at the beginning (always with a VersionInfo declaration), but the declaration is optional. There can be a DOCTYPE declaration. Finally, there must be a single element. The production Misc stands for a comment, a processing instruction, or whitespace.

The emitted events are now:

  • E_start_doc(version,dtd) is always emitted at the beginning. The version string is from VersionInfo, or "1.0" if the whole XML declaration is missing. The dtd object may contain the declaration of the parsed DOCTYPE clause. However, by setting parsing parameters it is possible to control which declarations are added to the dtd object.
  • If enable_super_root: E_start_super
  • If there are comments or processing instructions before the topmost element, and the node type is enabled, these events are now emitted.
  • Now the events of the topmost element follow.
  • If there are comments or processing instructions after the topmost element, and the node type is enabled, these events are now emitted.
  • If enable_super_root: E_end_super
  • E_end_doc name: ends the document. The name is the literal name of the topmost element, without any prefix normalization even if namespace processing is enabled
  • Finally, there is an E_end_of_stream event.
When the parser detects an error, it stops the event stream, and emits a last E_error event instead.

Calling the parser in event mode

The parser returns the emitted events while it is parsing. There are two models for that:

  • Push parsing: The caller passes a callback function to the parser, and whenever the parser emits an event, this function is invoked
  • Pull parsing: The parser runs as a coroutine together with the caller. The invocation of the parser returns the pull function. The caller now repeatedly invokes the pull function to get the emitted events until the end of the stream is indicated.
Let's look at both models in detail by giving an example. There is some code that is needed in both push and pull parsing. This example is similar to the examples given in Intro_getting_started. First we need a Pxp_types.source that says from where the input to parse comes. Second, we need an entity manager (of the opaque PXP type Pxp_entity_manager.entity_manager). The entity manager is a device that controls the source and switches between the entities to parse (if such switches are necessary). The entity manager is visible to the caller in event mode - in tree mode it is also needed but hidden in the parser driver.

let config = Pxp_types.default_config
let source = Pxp_types.from_file "filename.xml"
let entmng = Pxp_ev_parser.create_entity_manager config source

(See also: Pxp_ev_parser.create_entity_manager.)

From here on, the required code differs in both parsing modes.

Push parsing

The function Pxp_ev_parser.process_entity invokes the parser in push mode:

let () = Pxp_ev_parser.process_entity config entry entmng (fun ev -> ...)

The callback function is here shown as (fun ev -> ...). It is called back for every emitted event ev (of type Pxp_types.event). It is ensured that the last emitted event is either E_end_of_stream or E_error. See the documentation of Pxp_ev_parser.process_entity for details about error handling.

The parameter entry (of type Pxp_types.entry) determines the entry point in the XML grammar. Essentially, it says what kind of thing to parse. Most users will want to pass `Entry_document here to parse a closed document. Note that the emitted event stream includes the wrapping for documents as described in The wrapping for closed documents.

The entry point `Entry_content is for non-document external entities, as described in The wrapping for non-document entities. There is a similar entry point, `Entry_element_content, which additionally enforces some constraints on the node structure. In particular, there must be a single top-level element so that the enforced node structure looks like a document. We do not recommend to use `Entry_element_content - rather use `Entry_document, and remove the document wrapping in a postprocessing step.

The entry point `Entry_expr reads a single node (see Pxp_types.entry for details). It is recommended to use Pxp_ev_parser.process_expr instead of Pxp_ev_parser.process_entity together with this entry point, as this allows to start and end parsing within an entity, instead of having to parse an entity as a whole. (This is intended for special applications only.)

The entry point `Entry_declarations is currently unused.

Flags for `Entry_document. This entry point takes some flags as arguments that determine some details. It is usually ok to just pass the empty list of flags, i.e. `Entry_document []. The flags may enable some validation checks, or at least configure that some data is stored in the DTD object so that it is available for a later validation pass. Remember that the event mode by itself can only do well-formedness parsing. It can be reasonable, however, to enable flags when the event stream is later validated by some other means (e.g. by converting it into a tree and validating it).

Pull parsing

The pull parser is created by Pxp_ev_parser.create_pull_parser like:

let pull = create_pull_parser config entry entmng

The arguments config, entry, and entmng have the same meaning as for the push parser. In the case of the pull parser, however, no callback function is passed by the user. Instead, the return value pull is a function one can call to "pull" the events out of the parser engine. The pull function returns Some ev where ev is the event of type Pxp_types.event. After the end of the stream is reached, the function returns None.

Essentially, the parser works like an engine that can be started and stopped. When the pull function is invoked, the parser engine is "turned on", and runs for a while until (at least) the next event is available. Then, the engine is stopped again, and the event is returned. The engine keeps its state between invocations of pull so that the parser continues exactly at the point where it stopped the last time.

Note that files and other resources of the operating system are kept open while parsing is in progress. It is expected by the user to continue calling push until the end of the stream is reached (at least until Some E_end_of_stream, Some E_error, or None is returned by pull). See the description of Pxp_ev_parser.close_entities for a way of prematurely closing the parser for the exceptional cases where parsing cannot go on until the final parser state is reached.

Preprocessor

The PXP preprocessor (see Intro_preprocessor) allows one to create event streams programmatically. One can get the events either as list (type Pxp_types.event list), or in a form compatible with pull parsing. For example,

let book_list = 
  <:pxp_evlist< 
    <book>
      [ <title>[ "The Lord of The Rings" ]
        <author>[ "J.R.R. Tolkien" ]
      ]
  >>

returns the events as a Pxp_types.event list whereas

let pull_book = 
  <:pxp_evpull< 
    <book>
      [ <title>[ "The Lord of The Rings" ]
        <author>[ "J.R.R. Tolkien" ]
      ]
  >>

defines pull_book as an automaton from which one can pull the events like from a pull parser, i.e. pull_book is of type unit->Pxp_types.event option, and by calling it one can get the events one after the other. pull_book has the same type as the pull function returned by the pull parser.

For a more complete discussion see Generating events: pxp_evlist and pxp_evpull.

Note that the preprocessor does not add any wrapping for documents or non-documents to the event stream. See Documents for an example how to add such a wrapping in user code postprocessing step.

Push or pull?

The question arises whether one should prefer the push or the pull model. Generally, it is easy to turn a pull parser into a push parser by adding a loop that repeatedly invokes pull to get the events, and then calls the push function to deliver each event. There is no such possibility the other way round, i.e. one cannot take a push parser and make it look like a pull parser by wrapping it into some interface adapter - at least not in a language like O'Caml that does not know coroutines or continuations as language elements. Effectively, the pull model is the more general one.

The function Pxp_event.iter can be used to turn a pull parser into a push parser:

Pxp_event.iter push pull

The events pull-ed out of the parser engine are delivered one by one to the receiver by invoking push.

In PXP, the pull model is preferred, and a number of helper functions are only available for the pull model. If you need a push-stream nevertheless, it is recommended to use the pull parser, and to do all required transformations on it (like filtering, see below). Finally use Pxp_event.iter to turn the pull stream into a push-compatible stream.

Filters

Filters are a way to transform event streams (as defined for pull parsers). For example, one can remove the processing instruction events by doing (given that pull is the original parser, and we define now a modified pull' for the transformed stream):

let pull' = Pxp_event.pfilter
              (function
                | E_pinstr(_,_,_) -> false
                | _ -> true
              )
              pull

When events are read from pull', the events are also read from pull, but all processing instruction events are suppressed. Pxp_event.pfilter works a lot like List.filter - it only keeps the events in the stream for which a predicate function returns true.

Normalizing character data events

Pxp_event.norm_cdata_filter is a special predefined filter that transformes E_char_data events so that

  • empty E_char_data events are removed
  • adjacent E_char_data events are concatenated and replaced by a single E_char_data event
The filter is simply called by

let pull' = Pxp_event.norm_cdata_filter pull

Removing ignorable whitespace

In validation mode, the DTD may specify ignorable whitespace. This is whitespace for which is known it only exists to make the XML tree more readable (indentation etc.). In tree mode, ignorable whitespace is removed by default (see drop_ignorable_whitespace in Pxp_types.config).

It is possible to clean up the event stream in this way - although the event mode is not capable of doing a full validation of the XML document. It is required, however, that all declarations are added to the DTD object. This is done by setting the flags `Extend_dtd_fully or `Val_mode_dtd in the entry point, e.g. use

let entry = `Entry_document [`Extend_dtd_fully]

when you create the pull parser. The declarations of the XML elements are needed to check whether whitespace can be dropped.

The filter function is Pxp_event.drop_ignorable_whitespace_filter. Use it like

let pull' = Pxp_event.drop_ignorable_whitespace_filter pull

This filter does:

  • it checks whether non-whitespace is used in forbidden places, e.g. as children of an element that is declared with a regular expression content model
  • it removes E_char_data events only consisting of whitespace when they are ignorable.
The stream remains being normalized if it was already normalized, i.e. you can use this filter before or after Pxp_event.norm_cdata_filter.

Unwrapping documents

Sometimes it is necessary to get rid of the document wrapping. The filter Pxp_event.unwrap_document can do this. Call it like:

let get_doc_details, pull' = Pxp_event.unwrap_document pull

The filter removes all E_start_doc, E_end_doc, E_start_super, E_end_super, and E_end_of_stream events. Also, when an E_error event is encountered, the attached exception is raised. The information attached to the removed E_start_doc event can be retrieved by calling get_doc_details:

let xml_version, dtd = get_doc_details()

Note that this call will fail if there is no E_start_doc, and it can fail if it is not at the expected position in the stream. If you parse with the entry `Entry_document, this cannot happen, though.

It is allowed to call get_doc_details before using pull'.

Chaining filters

It is allowed to chain filters, e.g.

let pull1 = Pxp_event.drop_ignorable_whitespace_filter pull
let pull2 = Pxp_event.norm_cdata_filter pull1

Other helper functions

In Pxp_event there are also other helper functions besides filters. These functions can do:

  • conversion of pull streams to and from lists
  • concatenation of pull streams
  • extraction of nodes from pull streams
  • printing of pull streams
  • split namespace names

Events and namespaces

Namespace processing can also be enabled in event mode. This means that prefix normalization is applied to all names of elements and attributes. For example, this piece of code parses a file in event mode with enabled namespace processing:

  let nsmng = Pxp_dtd.create_namespace_manager()
  let config = 
        { Pxp_types.default_config with
             enable_namespace_processing = Some nsmng
        }
  let source = ...
  let entmng = Pxp_ev_parser.create_entity_manager config source
  let pull = create_pull_parser config entry entmng

The names returned in E_start_tag(name,attlist,scope_opt,entid) are prefix-normalized, i.e. name and the attribute names in attlist. The functions Pxp_event.namespace_split and Pxp_event.extract_prefix can be useful to analyze the names. For example, to get the namespace URI of an element name, do:

  match ev with
    | Pxp_types.E_start_tag(name,_,_,_) ->
        let prefix = Pxp_event.extract_prefix name in
        let uri = nsmng # get_primary_uri prefix in
        ...

Note that this may raise the exception Namespace_prefix_not_managed if the prefix is unknown or empty.

When namespace processing is enabled, the namespace scopes are included in the E_start_tag events. This can be used to get the display (original) prefix:

  match ev with
    | Pxp_types.E_start_tag(name,_,Some scope,_) ->
        let prefix = Pxp_event.extract_prefix name in
        let dsp_prefix = scope # display_prefix_of_normprefix prefix in
        ...

Note that this may raise the exception Namespace_prefix_not_managed if the prefix is unknown or empty, or Namespace_not_in_scope if the prefix is not declared for this part of the XML text.

Example: Print the events while parsing

The following piece of code parses an XML file in event mode, and prints the events. The reader is encouraged to modify the code by e.g. adding filters, to see the effect.

  let config = Pxp_types.default_config
  let source = Pxp_types.from_file "filename.xml"
  let entmng = Pxp_ev_parser.create_entity_manager config source
  let pull = create_pull_parser config entry entmng
  let () = Pxp_event.iter
             (fun ev -> print_endline (Pxp_event.string_of_event ev))
             pull

Connect PXP with a recursive-descent parser

We assume here that a list of integers like

   43 :: 44 :: []

is represented in XML as

  <list><cons><int>43</int><cons><int>44</int><nil/></cons></cons></list>

i.e. we have

  • list indicates that the single child is a list
  • cons has two children: the first is the head of the list, and the second the tail (think head :: tail in O'Caml)
  • nil is the empty list
  • int is an integer member of the list
We want to parse such XML texts by using the event-oriented parser, and combine it with a recursive-descent grammar. The XML parser delivers events which are taken as the tokens of the second parser.

let parse_list (s:string) =

  let rec parse_whole_list stream =
    (* Production:
         whole_list ::= "<list>" sub_list "</list>" END
     *)

    match stream with parser
        [< 'E_start_tag("list",_,_,_);
           l = parse_sub_list;
           'E_end_tag("list",_);
           'E_end_of_stream;
        >] ->
          l

  and parse_sub_list stream =
    (* Production:
         sub_list ::= "<cons>" object sub_list "</cons>"
                    | "<nil>" "</nil>"
     *)

    match stream with parser
        [< 'E_start_tag("cons",_,_,_); 
           head = parse_object;
           tail = parse_sub_list;
           'E_end_tag("cons",_)
        >] ->
          head :: tail
          
      | [< 'E_start_tag("nil",_,_,_); 'E_end_tag("nil",_) >] ->
          []

  and parse_object stream =
    (* Production:
         object ::= "<int>" text "</int>"
       with constraint that text is an integer parsable by int_of_string
     *)

    match stream with parser
        [< 'E_start_tag("int",_,_,_);
           number = parse_text;
           'E_end_tag("int",_)
        >] ->
          int_of_string number

  and parse_text stream =
    (* Production.
         text ::= "any XML character data"
     *)

    match stream with parser
        [< 'E_char_data data;
           rest = parse_text
        >] ->
          data ^ rest
      | [< >] ->
          ""
  in

  let config = 
    { Pxp_types.default_config with
        store_element_positions = false;
          (* don't produce E_position events *)
    }
  in
  let mgr = 
     Pxp_ev_parser.create_entity_manager
       config
       (Pxp_types.from_string s) in
  let pull = 
    Pxp_ev_parser.create_pull_parser config (`Entry_content[]) mgr in
  let pull' =
    Pxp_event.norm_cdata_filter pull in
  let next_event_or_error n =
    let e = pull' n in
    match e with
        Some(E_error exn) -> raise exn
      | _ -> e
  in
  let stream =
    Stream.from next_event_or_error in
  parse_whole_list stream

The trick is to use Stream.from to convert the "pull-style" event stream into a Stream.t. The kind of stream can be parsed in a recursive-descent way by using stream parser capability built into O'Caml.

Note that we normalize the character data nodes. The grammar can only process a single E_char_data event, and this normalization enforces that adjacent E_char_data events are merged.

Note that you have to enable camlp4 when compiling this example, because the stream parsers are only available via camlp4.

Escape PXP parsing

This feature is still considered as experimental!

It is possible to define two escaping functions in Pxp_types.config:

  • escape_contents: This function is called when one of the characters {, }, {{, or }} is found in character data context.
  • escape_attributes: This function is called when one of the mentioned special characters is found in the value of an attribute.
Both escaping functions are allowed to operate directly on the underlying lexical buffer PXP uses, and because of this these functions can interpret the following characters in an arbitrary special way. The escaping functions have to return a replacement text, i.e. a string that is to be taken as character data or as attribute value (depending on context).

Why are the curly braces taken as escaping characters? This is motivated by the XQuery language. Here, a single { switches from the XML object language to the XQuery meta language until another } terminates this mode. By doubling the brace character, it loses its escaping function, and a single brace character is assumed.

A simple example makes this clearer. We allow here that a number is written between curly braces in hexadecimal, octal or binary notation using the conventions of O'Caml. The number is inserted into the event stream in normalized decimal notation (i.e. no leading zeros). For instance, one can write

  <foo x="{0xff}" y="{{}}">{0o76}</foo>

and the parser emits the events

    E_start_tag("foo", ["x""255""y""{}" ], _, _)
    E_char_data("62")
    E_end_tag("foo",_)

Of course, this example is very trivial, and in this case, one could also get the same effect by postprocessing the XML events. We want to point out, however, that the escaping feature makes it possible to combine PXP with a foreign language with its own lexing and parsing functions.

First, we need a lexer - this is lex.mll:

  rule scan_number = parse
   | [ '0'-'9' ]+ 
        { `Int (int_of_string (Lexing.lexeme lexbuf)) }
   | ("0b"|"0B") [ '0'-'1' ]+ 
        { `Int (int_of_string (Lexing.lexeme lexbuf)) }
   | ("0o"|"0O") [ '0'-'7' ]+ 
        { `Int (int_of_string (Lexing.lexeme lexbuf)) }
   | ("0x"|"0X") [ '0'-'9' 'a'-'f' 'A'-'F' ]+ 
        { `Int (int_of_string (Lexing.lexeme lexbuf)) }
   | "}" 
        { `End }
   | _
        { `Bad }
   | eof
        { `Eof }

This lexer parses the various forms of numbers. We are lucky that we can use int_of_string to convert these forms to ints. The right curly brace is also recognized. Any other character leads to a lexing error (`Bad). If the XML file stops, `Eof is emitted.

Now the escape functions. escape_contents looks at the passed token. If it is a double curly brace, it immediately returns a single brace as replacement. A single left brace is processed by parse_number, defined below. A single right brace is forbidden. Any other tokens cannot be passed to escape_contents. escape_attributes has an additional argument, but we can ignore this for now. (This argument is the position in the attribute value, for advanced post-processing.)

  let escape_contents tok mng =
    match tok with
      | Lcurly (* "{" *) ->
          parse_number mng
      | LLcurly (* "{{" *) ->
          "{"
      | Rcurly (* "}" *) ->
          failwith "Single } not allowed"
      | RRcurly (* "}}" *) ->
          "}"
      | _ ->
          assert false

  let escape_attributes tok pos mng =
    escape_contents tok mng

Now, parse_number invokes our custom lexer Lex.scan_number with the (otherwise) internal PXP lexbuf. The function returns the replacement text.

It is part of the interface that the next token of the lexbuf must be the character following the right curly brace.

  let parse_number mng =
    let lexbuf = 
       match mng # current_lexer_obj # lexbuf with
         | `Ocamllex lexbuf -> lexbuf
         | `Netulex _ -> failwith "Netulex lexbufs not supported" in
    match Lex.scan_number lexbuf with
      | `Int n ->
           let s = string_of_int n in
           ( match  Lex.scan_number lexbuf with
               | `Int _ ->
                    failwith "More than one number"
               | `End ->
                    ()
               | `Bad ->
                    failwith "Bad character"
               | `Eof ->
                    failwith "Unexpected EOF"
           );
           s
      | `End ->
           failwith "Empty curly braces"
      | `Bad ->
           failwith "Bad character"
      | `Eof ->
           failwith "Unexpected EOF"

Due to the way PXP works internally, the method mng # current_lexobj # lexbuf can return two different kinds of lexical buffers. `Ocamllex means it is a Lexing.lexbuf buffer. This type of buffer is used for all 8 bit encodings, and if the special pxp-lex-utf8 lexer is used. The lexer pxp-ulex-utf8, however, will return a Netulex-style buffer.

Finally, we enable to use our escaping functions in the config record:

let config =
     { Pxp_types.default_config with
         escape_contents = escape_contents;
         escape_attributes = escape_attributes

How a complex example could work

The mentioned example is simple because the return value is a string. One can imagine, however, complex scenarios where one wants to insert custom events into the event stream. The PXP interface does not allow this directly. As workaround we suggest the following.

The custom events are collected in special buffers. The buffers are numbered by sequential integers (0, 1, ...). So escape_contents would allocate such a buffer and get a number:

  let buffer, n = allocate_event_buffer()

Here, buffer could be an event Queue.t. The number n identifies the buffer. The buffers, once filled, can be looked up by

  let buffer = lookup_event_buffer n

So escape_contents would like to return the events collected in the buffer, so that these are inserted into the event stream at the position where the curly escape occurs. As this is not allowed, it returns simply the buffer number instead so that it can be later identified, e.g.

  "{BUFFER " ^ string_of_int n ^ "}"

For unescaping curly braces one would insert special tokens, e.g. "{LCURLY}" and "{RCURLY}".

Now, the parser, specially configured with escape_contents, will return event streams where E_char_data events may include this special pointers to buffers {BUFFER <n>}, and the curly brace tokens {LCURLY} and {RCURLY}. In a postprocessing step, all occurrences of these tokens are localized in the event stream, and

  • for buffer tokens the buffer contents are looked up (lookup_event_buffer), and the events found there are substituted
  • for {LCURLY} an E_char_data "{" event is substituted
  • for {RCURLY} an E_char_data "}" event is substituted
It can be assumed that the tokens to localize are still E_char_data events of their own, i.e. not merged with adjacent E_char_data events.

It is admitted that this is a complicated workaround.

For attributes one can do basically the same. The postprocessing step may be a lot more complicated, however.
pxp-1.2.9/doc/manual/html/ref/type_Intro_events.html0000644000175000017500000000404213055274552021136 0ustar gerdgerd PXP Reference : Intro_events sig  endpxp-1.2.9/doc/manual/html/ref/Intro_resolution.html0000644000175000017500000007507313055274552021010 0ustar gerdgerd PXP Reference : Intro_resolution

Intro_resolution


Resolving entity ID's

One of the tasks of the XML parser is to open entities. Entities can be external files, but also strings, or channels, or anything that can be considered as a stream of bytes. Entities are identified by ID's. PXP knows four kinds of ID's:

  • SYSTEM ID's are URL's pointing to arbitrary resources. PXP includes only support for opening file URL's.
  • PUBLIC ID's are abstract names for entities, such as the well-known "-//W3C//DTD HTML 4.01//EN" string. Usually, PUBLIC ID's are accompanied by SYSTEM ID's to provide an alternate method for getting the entity.
  • Private ID's are a specialty of PXP. These ID's are used when no printable name is known, and the identity should be kept as an abstract property.
  • Anonymous ID's are an early form of private ID's that were used in ancient versions of PXP. They should no longer be used.
Resolution means now the following. The starting point is that we find a SYSTEM or PUBLIC identifier in the parsed XML text, or we have a private or anonymous identifier that was passed down by some user program. The second step is to make the identifier absolute. This step is only meaningful for SYSTEM identifiers, because they can be given by relative URL's. These URL's are made absolute. Finally, we run a lookup algorithm that gives us the entity to open back as stream of bytes. The lookup algorithm is highly configurable in PXP, and this chapter of the PXP manual explains how to do this.

Links to other documentation

  • Pxp_reader
  • Pxp_types.from_file
  • Pxp_types.from_string
  • Pxp_types.from_channel
  • Pxp_types.from_obj_channel
  • Specifying sources

Various types that are involved

The simple form of an (external) entity ID is Pxp_types.ext_id: It enumerates the four cases:

  • System url
  • Public(public_name, system_url)
  • Private p
  • Anonymous
Tip: To create an URL from a filename, use

let file_url = Pxp_reader.make_file_url filename
let file_url_string = Neturl.string_of_url file_url

During resolution, a different representation of the ID is preferred - Pxp_types.resolver_id:

type resolver_id = 
      { rid_private: private_id option;
        rid_public:  string option;
        rid_system:  string option;
        rid_system_base: string option;

A value of resolver_id can be thought as a matching criterion:

  • If rid_private is set to Some p, entities with an ext_id of Private p match the resolver_id.
  • If rid_public is set to Some public_name, entities with an ext_id of Public(public_name,_) match the resolver_id.
  • If rid_system is set to Some url, entities match the resolver_id when their ext_id is System url or Public(_,url).
It is sufficient that one of the criterions matches for associating the resolver_id with a particular entity. Note that Anonymous is missing in this list - it simply matches with any resolver_id.

The resolver_id value can be modified during the resolution process, for example by rewriting. For example, one could rewrite all URL's http://sample.org to some local file URL's when the contents of this web site are locally available.

It is not said that rid_system is already an absolute URL when the resolution process starts. It is usually rewritten into an absolute URL during this process. For that reason, we also remember rid_system_base. This is the base URL relative to which the URL in rid_system is to be interpreted.

The resolution algorithm is expressed as Pxp_reader.resolver. This is an object providing a method open_rid (open by resolver ID) that takes a resolver_id as input, and returns the opened entity. There are a number of predefined classes in Pxp_reader for setting up resolver objects. Some classes can even be used to construct more complex resolvers from simpler ones, i.e. there is resolver composition.

Besides Pxp_reader.resolver, there are also sources, type Pxp_types.source. Sources are concrete applications of resolvers to external ID's, i.e. they represent the task of opening an entity with a certain algorithm, applied to a certain ID. There are several ways of constructing sources. First, one can directly use the source values Entity, ExtID or XExtID. Second, there are a number of functions for creating common cases of sources, e.g. Pxp_types.from_file.

For example, to open the ext_id value e with a resolver r, the source has to be

 let source = ExtID(e,r) 

There is also XExtID which allows one to set the base URL in the resolver_id, and for very advanced cases there is Entity (which is beyond an introduction).

How to use the following list of classes

We give a short summary of the function provided by the resolver class. Some classes provide quite low-level functionality, especially those named resolve_to_*. A beginner should avoid them.

Every resolver matches the ID to open with some criterion of ID's the resolver is capable to open. If this matching is successul we also say the resolver accepts the ID. After being accepted the rest of the resolution process is deemed to be successful, e.g. a non-existing file will lead to a "file not found" error. Not accepting an ID means that in a composed resolver another part resolver might get the chance, and tries to open it.

We especially mention whether relative URL's are specially handled (i.e. converted to absolute URL's). If not, but you would like to support relative URL's, it is always possible to wrap the resolver into norm_system_id. This is generally recommended.

Some resolvers can only be used once because the entity is "consumed" after it has been opened and the XML text is read. Think of reading from a pipe.

Also note that you can combine all resolvers with the from_* functions in Pxp_types, e.g.

let source = Pxp_types.from_file 
               ~alt:r
               filename

The resolver given in alt is tried when the resolver built-in to from_file does not match the input ID. Here, from_file only matches file URL's, so everything else is passed down to alt, e.g. PUBLIC names.

List of base resolver classes

These classes open certain entities. Some also allow you to pass the resolution process over to a subresolver, but the resolver_id is not modified.

resolve_to_this_obj_channel

  • Link: Pxp_reader.resolve_to_this_obj_channel
  • What is opened: An already existing Netchannels.in_obj_channel
  • Which ID's are opened: any ext_id
  • Matching criteron: The resolver is successful when the ID to open is equal to a constant ext_id or resolver_id
  • Relative URL's: are not specially handled
  • Can be used several times: no
Example.

This example matches against the id argument, and reads from the object channel ch when the resolver matches:

let ch = new Netchannels.string_channel "<foo></foo>"
let r = new Pxp_reader.resolve_to_this_obj_channel
              ~id:(Public("-//FOO//"""))
              ()
              ch

This is a one-time resolver because the data of ch is consumed afterwards.

resolve_to_any_obj_channel

  • Link: Pxp_reader.resolve_to_any_obj_channel
  • What is opened: An Netchannels.in_obj_channel that is created for every matched ID
  • Which ID's are opened: any ext_id
  • Matching criterion: An arbitrary matching function can be passed
  • Relative URL's: are not specially handled
  • Can be used several times: yes

resolve_to_url_obj_channel

  • Link: Pxp_reader.resolve_to_url_obj_channel
  • What is opened: An Netchannels.in_obj_channel that is created for every matched ID
  • Which ID's are opened: formally any ext_id, but this resolver is only reasonable for SYSTEM ID's.
  • Matching criterion: Matching functions can be passed, but there is already some built-in logic for URL matching
  • Relative URL's: are made absolute before matching
  • Can be used several times: yes

resolve_as_file

  • Link: Pxp_reader.resolve_as_file
  • What is opened: Files
  • Which ID's are opened: SYSTEM or PUBLIC ID's with an url using file
  • Matching criterion: the resolver is successful for all file URL's, no matter of whather the files exist or not (will lead later to an error)
  • Relative URL's: are made absolute before matching
  • Can be used several times: yes
Example.

let r = new Pxp_reader.resolve_as_file ()

If the file "/data/foo.xml" exists, and the user wants to open SYSTEM "file://localhost/data/foo.xml" this resolver will do it.

lookup_id

  • Link: Pxp_reader.lookup_id
  • What is opened: After matching, a subresolver of any kind is invoked.
  • Which ID's are opened: any ext_id
  • Matching criterion: A catalog of acceptable ext_id's maps to the subresolvers
  • Relative URL's: are not specially handled
  • Can be used several times: yes

lookup_id_as_file

  • Link: Pxp_reader.lookup_id_as_file
  • What is opened: files
  • Which ID's are opened: any ext_id
  • Matching criterion: A catalog of acceptable ext_id's maps to file names
  • Relative URL's: are not specially handled
  • Can be used several times: yes
Example.

let r = new Pxp_reader.lookup_id_as_file
          [ System "http://foo.org/file.xml""/data/download/foo.org/file.xml";
            Private p, "/data/private/secret.xml"
          ]

If the user opens SYSTEM "http://foo.org/file.xml", the file /data/download/foo.org/file.xml is opened. Note that relative URL's are not handled. To enable that, wrap r into a norm_system_id resolver.

If the user opens the private ID p, the file /data/private/secret.xml is opened.

lookup_id_as_string

  • Link: Pxp_reader.lookup_id_as_string
  • What is opened: constant strings
  • Which ID's are opened: any ext_id
  • Matching criterion: A catalog of acceptable ext_id's maps to string constants
  • Relative URL's: are not specially handled
  • Can be used several times: yes
Example. We want to parse a private ID whose corresponding entity is given as constant string:

let p = alloc_private_id()
let r = new Pxp_reader.lookup_id_as_string
          [ Private p, "<foo>data</foo>" ]
let source = ExtID(Private p, r)

lookup_public_id

  • Link: Pxp_reader.lookup_public_id
  • What is opened: After matching, a subresolver of any kind is invoked.
  • Which ID's are opened: PUBLIC ID's by included public_name
  • Matching criterion: A catalog of acceptable public_name's maps to the subresolvers
  • Relative URL's: n/a
  • Can be used several times: yes

lookup_public_id_as_file

  • Link: Pxp_reader.lookup_public_id_as_file
  • What is opened: files
  • Which ID's are opened: PUBLIC ID's by included public_name
  • Matching criterion: A catalog of acceptable public_name's maps to file names
  • Relative URL's: n/a
  • Can be used several times: yes

lookup_public_id_as_string

  • Link: Pxp_reader.lookup_public_id_as_string
  • What is opened: constant strings
  • Which ID's are opened: PUBLIC ID's by included public_name
  • Matching criterion: A catalog of acceptable public_name's maps to string constants
  • Relative URL's: n/a
  • Can be used several times: yes

lookup_system_id

  • Link: Pxp_reader.lookup_system_id
  • What is opened: After matching, a subresolver of any kind is invoked.
  • Which ID's are opened: SYSTEM or PUBLIC ID's by included url
  • Matching criterion: A catalog of acceptable url's maps to the subresolvers
  • Relative URL's: are not specially handled
  • Can be used several times: yes

lookup_system_id_as_file

  • Link: Pxp_reader.lookup_system_id_as_file
  • What is opened: files
  • Which ID's are opened: SYSTEM or PUBLIC ID's by included url
  • Matching criterion: A catalog of acceptable url's maps to file names
  • Relative URL's: are not specially handled
  • Can be used several times: yes

lookup_system_id_as_string

  • Link: Pxp_reader.lookup_system_id_as_string
  • What is opened: constant strings
  • Which ID's are opened: SYSTEM or PUBLIC ID's by included url
  • Matching criterion: A catalog of acceptable url's maps to string constants
  • Relative URL's: are not specially handled
  • Can be used several times: yes
Example. See below at norm_system_id

List of rewriting resolver classes

These classes pass the resolution process over to a subresolver, and the resolver_id to open is rewritten before the subresolver is invoked. Note that the rewritten ID is only visible in the subresolver, e.g. in

let r = new Pxp_reader.combine
          [ new Pxp_reader.norm_system_id sub_r1;
            sub_r2
          ]

the class norm_system_id rewrites the ID, and this is only visible in sub_r1, but not in sub_r2.

norm_system_id

  • Link: Pxp_reader.norm_system_id
  • What is opened: after rewriting, a subresolver of any kind is invoked
  • Which ID's are opened: any ext_id
  • Matching criterion: all ID's are accepted (except an error occurs during ID rewriting)
  • Rewriting: ID's including an URL are made absolute
  • Relative URL's: this class exists specifically to make any relative URL's absolute for the subresolver
  • Can be used several times: yes
Example.

let r = new Pxp_reader.norm_system_id
          (new lookup_system_id_as_string
             [ "http://foo.org/file1.xml""<foo>&file2;</foo>";
               "http://foo.org/file2.xml""<bar>data</bar>";
             ]
          )

We also assume here that the general entity file2 is declared as SYSTEM "file2.xml", i.e. with a relative URL. (The declaration should be added to the file1 XML text to make the example complete.) The resolver norm_system_id adds the support for relative URL's that is otherwise missing in lookup_system_id_as_string. The XML parser would read the text "<foo><bar>data</bar></foo>".

Without norm_system_id, the user can only open the ID's when they are exactly given as in the catalog list, e.g. as SYSTEM "http://foo.org/file1.xml".

rewrite_system_id

  • Link: Pxp_reader.rewrite_system_id
  • What is opened: after rewriting, a subresolver of any kind is invoked
  • Which ID's are opened: any ext_id
  • Matching criterion: ID's are matched against a substitution
  • Rewriting: If a matching substitution is found, it is applied
  • Relative URL's: URL's are made absolute before matching starts
  • Can be used several times: yes
Example. All files of foo.org are locally available, and so foo.org URL's can be rewritten to file URL's:

let r =
  new Pxp_reader.rewrite_system_id
    [ "http://foo.org/""file:///usr/share/foo.org/"
    ]
    (new Pxp_reader.resolve_as_file())

Alternation of resolvers

combine

  • Link: Pxp_reader.combine
  • What is opened: one of a list of subresolvers is invoked
  • Which ID's are opened: any ext_id
  • Matching criterion: The subresolvers are tried in turn to open the entity. If one of them matches against the ID, the combined resolver also matches (i.e. this is an "OR" logic)
  • Relative URL's: are not specially handled
  • Can be used several times: yes

pxp-1.2.9/doc/manual/html/ref/type_Intro_resolution.html0000644000175000017500000000404613055274552022041 0ustar gerdgerd PXP Reference : Intro_resolution sig  endpxp-1.2.9/doc/manual/html/ref/Intro_getting_started.html0000644000175000017500000020734513055274552021773 0ustar gerdgerd PXP Reference : Intro_getting_started

Intro_getting_started


In the following sections we'll explain how to solve a basic task in PXP, namely to parse a file and to represent it in memory, followed by paragraphs on variations of this task, because not everybody will be happy with the basic solution.

Parse a file and represent it as tree

The basic piece of code to parse "filename.xml" is:

let config = Pxp_types.default_config
let spec = Pxp_tree_parser.default_spec
let source = Pxp_types.from_file "filename.xml"
let doc = Pxp_tree_parser.parse_document_entity config source spec

As you can see, a some defaults are loaded (Pxp_types.default_config, and Pxp_tree_parser.default_spec). These defaults have these effects (as far as being important for an introduction):

  • The parsed document is represented in ISO-8859-1. The file can be encoded differently, however, and if so, it is automatically recoded to ISO-8859-1.
  • The generated tree only has nodes for elements and character data sections, but not for comments, and processing instructions.
  • The top-most node of the tree, doc#root, is the top-most element.
  • No namespace processing is performed.
XML does not know the concept of file names. All files (or other resources) are named by so-called ID's. Although we can pass here a file name to from_file, it is immediately converted into a SYSTEM ID which is essentially a URL of the form file:///dir1/.../dirN/filename.xml. This ID can be processed - especially it is now clear how to treat releative SYSTEM ID's that occur in the parsed document. For instance, if another file is included by "filename.xml", and the SYSTEM ID is "parts/part1.xml", the usual rules for resolving relative URL's say that the effective file to read is file:///dir1/.../dirN/parts/part1.xml. Relative SYSTEM ID's are resolved relative to the URL of the file where the entity reference occurs that leads to the inclusion of the other file (this is comparable to how hyperlinks in HTML are treated).

Note that we make here some assumptions about the file system of the computer. Pxp_reader.make_file_url has to deal with character encodings of file names. It assumes UTF-8 by default. By passing arguments to this function, other assumptions about the encoding of file names can be made. Unfortunately, there is no portable way of determining the character encoding the system uses for file names (see the hyperlinks at the end of this section).

The returned doc object is of type Pxp_document.document. This type is used for all regular documents that exist independently. The root of the node tree is returned by doc#root which is a . See Intro_trees for more about the tree representation.

The call Pxp_tree_parser.parse_document_entity does not only parse, but it also validates the document. This works only if there is a DTD, and the document conforms to the DTD. There is a weaker criterion for formal correctness called well-formedness. See below how to only the check for well-formedness while parsing without doing the whole validation.

Links about the file name encoding problem:

It is strongly recommended to compile and link with the help of ocamlfind. For (byte) compiling use one of

  • ocamlfind ocamlc -package pxp-engine -c file.ml
  • ocamlfind ocamlc -package pxp -c file.ml
The package pxp-engine refers to the core library while pxp refers to an extended version including the various lexers. For compiling, there is no big difference between the two because the lexers are usually not directly invoked. However, at link time you need these lexers. You can choose between using the pre-defined package pxp and a manually selected combination of pxp-engine with some lexer packages. So for linking e.g. use one of:

  • ocamlfind ocamlc -package pxp -linkpkg -o executable ... to get the standard selection of lexers
  • ocamlfind ocamlc -package pxp-engine,pxp-lex-iso88591,pxp-ulex-utf8 -linkpkg -o executable ... to get lexers for ISO-8859-1 and UTF-8
There is a special lexer for every choice of encoding for the internal representation of XML. If you e.g. choose to represent the document as UTF-8 there must be a lexer capable of handling UTF-8. The package pxp includes a standard set of lexers, including UTF-8 and many encodings of the ISO-8859 series. For more about encodings, see below Encodings.

Variations

Catching and printing exceptions

The relevant exceptions are defined in Pxp_types. You can catch these exceptions (as thrown by the parser) as in:

try ...
with
  | Pxp_types.Validation_error _
  | Pxp_types.WF_error _
  | Pxp_types.Namespace_error _
  | Pxp_types.Error _
  | Pxp_types.At(_,_) as error ->
      print_endline ("PXP error " ^ Pxp_types.string_of_exn error)

There are more exceptions, but these are usually caught within PXP and converted to one of the mentioned exceptions.

Printing trees in the O'Caml toploop

There are toploop printers for nodes and documents. They are automatically activated when the findlib directive #require "pxp" is used to load PXP into the toploop. Alternatively, one can also do

#install_printer Pxp_document.print_node;;
#install_printer Pxp_document.print_doc;;

For example, the tree <x><y>foo</y></x> would be shown as:

  # tree;;
  _ : ('Pxp_document.node Pxp_document.extension as 'a) Pxp_document.node =
  * T_element "x"
    * T_element "y"
      * T_data "foo"

Parsing in well-formedness mode

In well-formedness mode many checks are not performed regarding the formal integrity of the document. Note that the terms "valid" and "well-formed" are rigidly defined in the XML standard, and that PXP strictly tries to conform to the standard. Especially note that the DOCTYPE clause is not rejected in well-formedness mode and that the declarations are parsed although interpreted differently.

In order to call the parser in well-formedness mode, call one of the "wf" functions, e.g.

let doc = Pxp_tree_parser.parse_wfdocument_entity config source spec

Details. Even in well-formedness mode there is a DTD object. The DTD object is, however, differently treated:

  • All declarations are parsed. However, the declarations of elements, attributes, and notations are not added to the DTD object. The declarations of entities are fully processed. Processing instructions are also not handled in any way differently than when validation is enabled. Note that all this means that you can get syntax errors about ill-formed declarations in well-formedness mode, although the declarations are not further processed.
  • When the parser checks the integrity of elements, attributes or notations it finds in the XML text to parse, it accepts that there is no declaration in the DTD object. This is controlled by a special DTD mode called arbitrary_allowed (see Pxp_dtd.dtd.allow_arbitrary). If enabled as done in well-formedness mode, the DTD reacts specially when a declaration is missing so that the parser knows it has to accept that. Note that, if one added a declaration programmatically to the DTD object, the DTD would find it, and would actually validate against it. Effectively, validation is not disabled in well-formedness mode, only the constraints imposed by the DTD object on the document are weaker. There is in fact a way to add declarations in well-formedness mode to get partly the effects of validation: This is called The mixed mode.
  • It is not checked whether the top-most element is the one declared in the DOCTYPE clause (if that clause exists).
When processing well-formed documents one should be more careful because the parser has not done any checks on the structure of the node tree.

Validating well-formed trees

It is possible to validate a tree later that was originally only parsed in well-formedness mode.

Of course, there is one obvious difficulty. As mentioned in the previous section, the DTD object is incompletely built (declarations of elements, attributes, and notations are ignored), so the DTD object is not suitable for validating the document against it. For validation, however, a complete DTD object is required. The solution is to replace the DTD object by a different one. As the DTD object is referenced from all nodes of the tree, and thus intricately connected with it, the only way to do so is to copy the entire tree. The function Pxp_marshal.relocate_subtree can be used for this type of copy operation.

We assume here that we can get the replacement DTD from an external file, "file.dtd", and that another constraint is that the root element must be start (as if we had <!DOCTYPE start SYSTEM "file.dtd">). Also doc is the parsed "filename.xml" file as retrieved by

let config = Pxp_types.default_config
let spec = Pxp_tree_parser.default_spec
let source = Pxp_types.from_file "filename.xml"
let doc = Pxp_tree_parser.parse_wfdocument_entity config source spec

Now the validation against a different DTD is done by:

let rdtd_source = Pxp_types.from_file "file.dtd"
let rdtd = Pxp_dtd_parser.parse_dtd_entity config rdtd_source
let () = rdtd # set_root "start"
let vroot = Pxp_marshal.relocate_subtree doc#root rdtd spec
let () = Pxp_document.validate vroot
let vdoc = new Pxp_document.document config.warner config.encoding
let () = vdoc#init_root vroot doc#raw_root_name

The vdoc document has now the same contents as doc but points to a different DTD, namely rdtd. Also, the validation checks have been performed. A few more comments:

  • We use here the same config for parsing the original document doc and the replacement DTD rdtd. This is not strictly required. However, the encoding of the in-memory representation must be identical (i.e. config.encoding).
  • When you omit rdtd#set_root, any root element is allowed.
  • The entity definitions of the old DTD object are lost.
  • It is of course possible to modify doc before doing the validation, or to validate a doc that is not the result of a parser call but programmatically created.

Encodings

In PXP, the encoding of the parsed text (the external encoding), and the encoding of the in-memory representation can be distinct. For processing external encodings PXP relies on Ocamlnet. The external encoding is usually indicated in the XML declaration at the beginning of the text, e.g.

<?xml version="1.0" encoding="ISO-8859-2"?>
...

There is also an autorecognition of the external encoding that works for UTF-8 and UTF-16.

It is generally possible to override the external encoding (e.g. because the file has already been converted but the XML declaration was not changed at the same time). Some of the from_* sources allow it to override the encoding directly, e.g. by setting the fixenc argument when calling Pxp_types.from_channel. Note that Pxp_types.from_file does not have this option as this source allows it to read any file. Overriding encodings is, however, only interesting for certain files. A workaround is to combine from_file with a catalog of ID's, and to override the encodings for certain files there. (Catalogs also allow to override external encodings. See below, Specifying sources for examples using catalogs.)

As mentioned, the encoding of the in-memory representation can be distinct from the external encoding. It is required that every character in the document can be represented in the representation encoding. Because of this, the chosen encoding should be a superset of all external encodings that may occur. If you choose UTF-8 for the representation every character can be represented anyway.

You set the representation encoding in the config record, e.g.

let config =
  { Pxp_types.default_config
      with encoding = `Enc_utf8
  }

It is strictly required that only a single encoding is used in a document (and PXP also checks that).

The available encodings for the in-memory representation are a subset of the encodings supported by Ocamlnet. Effectively, UTF-8 is supported and a number of 8-bit encodings as far as they are ASCII- compatible (i.e. extensions of 7 bit ASCII).

For every representation encoding PXP needs a different lexer. PXP already comes with a set of lexers for the supported encodings. However, at link time the user program must ensure that the lexer is linked into the executable. The lexers are available as separate findlib packages:

  • pxp-ulex-utf8: This is the standard lexer for UTF-8
  • pxp-wlex-utf8: This is the old, wlex-based lexer for UTF-8. It is not built when ulex is available.
  • pxp-lex-utf8: This is the old, ocamllex-based lexer for UTF-8. It is slightly faster than pxp-ulex-utf8, but consumes a lot more memory.
  • pxp-lex-*: These are lexers for various 8 bit character sets
For the link command, see above: Compiling and linking.

Event parser (push/pull parsing)

It is sometimes not desirable to represent the parsed XML data as tree. An important reason is that the amount of data would exceed the available memory resources. Another reason may be to combine XML parsing with a custom grammar. In order to support this, PXP can be called as event parser. Basically, PXP emits events (tokens) while parsing certain syntax elements, and the caller of PXP processes these events. This mode can only be used together with well-formedness mode - for validation the tree representation is a prerequisite.

Here we show how to parse "filename.xml" with a pull parser:

let config = Pxp_types.default_config
let source = Pxp_types.from_file "filename.xml"
let entmng = Pxp_ev_parser.create_entity_manager config source
let entry = `Entry_document []
let next = Pxp_ev_parser.create_pull_parser config entry entmng

Now, one can call next() repeatedly to get one event after the other. The events have type Pxp_types.event option.

More about event parsing can be found in Intro_events.

Low-profile trees

When the tree classes in Pxp_document are too much overhead, it is easily possible to define a specially crafted tree data type, and to transform the event-parsed document into such trees. For example, consider this cute definition:

type tree =
  | Element of string * (string * string) list * tree list
  | Data of string

A tree node is either an Element(name,atts,children) or a Data(text) node. Now we event-parse the XML file:

let config = Pxp_types.default_config
let source = Pxp_types.from_file "filename.xml"
let entmng = Pxp_ev_parser.create_entity_manager config source
let entry = `Entry_document []
let next = Pxp_ev_parser.create_pull_parser config entry entmng

Finally, here is a function build_tree that calls the next function to build our low-profile tree:

let rec build_tree() =
  match next() with
    | Some (E_start_tag(name,atts,_,_)) ->
        let children = build_children [] in
        let tree = Element(name,atts,children) in
        skip_rest();
        tree
    | Some (E_error e) ->
        raise e
    | Some _ ->
        build_tree()
    | None ->
        assert false     

and build_node() =
  match next() with
    | Some (E_char_data data) ->
        Some(Data data)
    | Some (E_start_tag(name,atts,_,_)) ->
        let children = build_children [] in
        Some(Element(name,atts,children))
    | Some (E_end_tag(_,_)) ->
        None
    | Some (E_error e) ->
        raise e
    | Some _ ->
        build_node()
    | None ->
        assert false

and build_children l =
  match build_node() with
    | Some n -> build_children (n :: l)
    | None -> List.rev l
    
and skip_rest() =
  match next() with
    | Some E_end_of_stream ->
        ()
    | Some (E_error e) ->
        raise e
    | Some _ ->
        skip_rest()
    | None ->
        assert false

Of course, this all is only reasonable for the well-forermedness mode, as PXP's validation routines depend on the built-in tree representation of Pxp_document.

Choosing the node types to represent

By default, PXP only represents element and data nodes (both in the normal tree representation and in the event stream). It is possible to enable more node types:

  • Comment nodes are created for XML comments. In the tree representation, the node type T_comment is used for them. In the event stream, the event type E_comment is used.
  • Processing instruction nodes are created for processing instructions (PI's) occuring in the normal XML flow (i.e. outside of DTD's). In the tree representation, the T_pinstr node type is used, and in the event stream, the event type E_pinstr is used.
  • The super root node can be put at the top of the tree, so that the top-most element is a child of this node. This can be reasonable especially when comment nodes and PI nodes are also enabled, because when these nodes surround the top-most element they also become children of the super root node. In the tree representation, the T_super_root node type is used, and in the event stream, the event type E_start_super marks the beginning of this node, and E_end_super marks the end of this node.
These node types are enabled in the config record, e.g.

let config =
  { Pxp_types.default_config
      with enable_comment_nodes = true;
           enable_pinstr_nodes = true;
           enable_super_root_node = true 
  }

Note that the "super root node" is sometimes called "root node" in various XML standards giving semantical model of XML. For PXP the name "super root node" is preferred because this node type is not obligatory, and the top-most element node can also be considered as root of the tree.

Controlling whitespace

Depending on the mode, PXP applies some automatic whitespace rules. The user can call functions to reduce whitespace even more.

In validating mode, there are whitespace rules for data nodes and for attributes (the latter below). In this mode it is possible that an element x is declared such that a regular expression describes the permitted children. For instance,

 <!ELEMENT x (y,z)> 

is such a declaration, meaning that x may only have y and z as children, exactly in this order, as in

 <x><y>why</<y><z>zet</z></x> 

XML, however, allows that whitespace is added to make such terms more readable, as in

 
<x>
  <y>why</<y>
  <z>zet</z>
</x> 

The additional whitespace should not, however, appear as children of node x, because it is considered as a purely notational improvement without impact on semantics. By default, PXP does not create data nodes for such notational whitespace. It is possible to disable the suppression of this type of whitespace by setting drop_ignorable_whitespace to false:

  let config =
    { Pxp_types.default_config 
        with drop_ignorable_whitespace = false
    }

In well-formedness mode, there is no such feature because element declarations are ignored.

Note that although in event mode the parser is restricted to well-formedness parsing, it is still possible to get the effect of drop_ignorable_whitespace. See Pxp_event.drop_ignorable_whitespace_filter for how to selectively enable this validation feature.

The other whitespace rules apply to attributes. In all modes line breaks in attribute values are converted to spaces. That means a1 and a2 have identical values:

<x a1="1 2" a2="1
2"
 a3="1&#10;2"/>

It is possible to suppress this conversion by using &#10; as line separator, as in a3, which truly includes a line-feed character.

In validating mode only there are more rules because attributes are declared. If the attribute is declared with a list value (IDREFS, ENTITIES, or NMTOKENS), any amount of whitespace can be used to separate the list elements. PXP returns the value as Valuelist l where l is an O'Caml list of strings.

If the tree representation is chosen, the function Pxp_document.strip_whitespace can be called to reduce the amount of whitespace in data nodes.

Checking the ID consistency and looking up nodes by ID

In XML it is possible to identify elements by giving them an ID attribute. The requires a DTD, and could be done with declarations like

  <!ATTLIST x id ID #REQUIRED>

meaning that element x has a mandatory attribute id with the special ID property: Every node must have a unique id value.

In the same context, it is possible to declare attributes as references to other nodes, expressed by denoting the id of the other node:

  <!ATTLIST y r IDREF #IMPLIED>

Here, the (optional) attribute r of y is a reference to another node. It is only allowed to put identifiers into such attributes that also occur in the ID of another node.

By default, PXP does neither check the uniqueness of ID-declared attributes nor the existence of the nodes referenced by IDREF-declared attributes. In tree mode, it is possible to enable that, however.

For that purpose, one has to create an Pxp_tree_parser.index. If passed to the parser function, the parser adds the ID-values of all nodes to the index, and checks whether every ID value is unique. Additionally, when one enables the idref_pass the parser also checks whether IDREF attributes only point to existing nodes. The code:

let config = { Pxp_types.default_config with idref_pass = true }
let spec = Pxp_tree_parser.default_spec
let source = Pxp_types.from_file "filename.xml"
let hash_index = new Pxp_tree_parser.hash_index
let id_index = (hash_index :> _ Pxp_tree_parser.hash_index)
let doc = Pxp_tree_parser.parse_document_entity ~id_index config source spec

The difference between hash_index and id_index is that the former object has one additional method index returning the whole index.

The id_index may also be useful after the document has been parsed. The code processing the parsed documennt can take advantage of it by looking up nodes in it. For example, to find the node identified by "foo", one can call

 id_index # find "foo" 

which either returns this node, or raises Not_found.

Note that the id_index is not automatically updated when the parsed tree is modified.

Finding nodes by element names

As we are at it: PXP does not maintain indexes of any kind. Unlike in other tree representations, there is no index of elements that would help one to quickly find elements by their names. The reason for this omission is that such indexes need to be updated when the tree is modified, and these updates can be quite expensive operations.

The ID index explained in the last section is not automatically updated, and it has only been added to comply fully to the XML standard (which demands ID checking).

Nevertheless, one can easily define indexes of one own (and for the advanced programmer it might be an interesting task to develop an extension module to PXP that generically solves this problem). For instance, here is an index of elements:

  let index = Hashtbl.create 50

  Pxp_document.iter_tree
    ~pre:(fun node ->
             match node with
               | T_element name -> Hashtbl.add index name node
               | _ -> ()
         )
    doc#root

Now, Hashtbl.find can be used to get the last occurrence, and Hashtbl.find_all to get all occurrences.

If it is not worth-while to build an index, one can also call the functions Pxp_document.find_element and Pxp_document.find_all_elements, but these functions rely on linear searching.

Specifying sources

The Pxp_types.source says from where the data to parse comes. The task of the source is more complex as it looks at the first glance, as it not only says from where the initially parsed entity comes, but also from where further entities can be loaded that are referenced and included by the first one.

The mentioned function Pxp_types.from_file allows that all files can be opened as entities, and maps the SYSTEM identifiers to file names. It is very powerful.

There are three more from_* functions:

  • Pxp_types.from_string gets the data from a string
  • Pxp_types.from_channel gets the data from an in_channel
  • Pxp_types.from_obj_channel gets the data from an in_obj_channel (an Ocamlnet definition)
These three variants differ from from_file in so far as only one entity can be parsed at all (unless one passes alternate resolvers to them). This means it is not possible that the initially parsed entity includes data from another entity. Example code:

 let source = Pxp_types.from_string "<?xml version='1.0'?><foo/>" 

So the source mechanism has these limitations:

  • The Pxp_types.from_file function allows one to read from all files by using SYSTEM URL's of the form file:///path. It is not possible to restrict the file access in any way. There is no support for PUBLIC identifiers.
  • The other functions like Pxp_types.from_string allow one to parse data coming from everywhere, and it is not possible to access any files (as it is not possible to open any further external entity).
There is the Pxp_reader module with a very powerful abstraction called Pxp_reader.resolver. There are resolvers for files, for alternate resources like data channels, and there is the possibility of building more complex resolvers by composing simpler ones.

Please see Pxp_reader and Intro_resolution for deeper explanations. Here are the most important recipes to use this advanced mechanism:

Read from files, and define a catalog of exceptions:

let catalog =
 new Pxp_reader.lookup_id_as_file
  [ System("http://foo.org/our.dtd"), "/usr/share/foo.org/out.dtd";
    Public("-//W3C//DTD XHTML 1.0 Strict//EN",""), "/home/stuff/xhtml_strict.dtd"
  ]
let source = Pxp_types.from_file ~alt:[catalog] "filename.xml"

This allows one to open all local files using the file:///path URL's, but also maps the SYSTEM ID "http://foo.org/our.dtd" and the PUBLIC ID "-//W3C//DTD XHTML 1.0 Strict//EN" to local files.

There is also Pxp_reader.lookup_id_as_string mapping to strings.

Read from files, but restrict access, and map URL's

let resolver =
  new Pxp_reader.rewrite_system_id
    [ "http://foo.org/""file:///usr/share/foo.org";
      "file:///""file:///home/stuff/localxml"
    ]
    (new Pxp_reader.resolve_as_file())
let file_url = Pxp_reader.make_file_url "filename.xml"
let source = ExtID(System((Neturl.string_of_url file_url), resolver)

This allows one to open entities from the whole http://foo.org/ hierarchy, but the data is not downloaded by HTTP, but instead assumed to reside in the local directory hierarchy /usr/share/foo.org. Also, the whole file:/// hierarchy is re-rooted to /home/stuff/localxml. As the URL's are normalized before any access is tried, this scheme provides access protection to other parts of the file system (i.e. one cannot escape from the new root by "..").

In order to combine with a catalog as defined above, use

let resolver =
  new Pxp_reader.combine
    [ catalog;
      new Pxp_reader.rewrite_system_id ...
    ]

Virtual entity hierarchy

Given we have the three identifiers

  • http://virtual.com/f1.xml
  • http://virtual.com/f2.xml
  • http://virtual.com/f3.xml
and these identifiers include each other by using relative SYSTEM ID's, and we have O'Caml strings f1_xml, f2_xml, and f3_xml with the contents, we want to make the virtual.com hierarchy available while parsing from a string s.

let resolver =
  new Pxp_reader.norm_system_id
    (new Pxp_reader.lookup_id_as_string
       [ "http://virtual.com/f1.xml"; f1_xml;
         "http://virtual.com/f2.xml"; f2_xml;
         "http://virtual.com/f3.xml"; f3_xml
       ]
    )
let source = Pxp_types.from_string ~alt:[resolver] s

The trick is Pxp_reader.norm_system_id. This class makes it possible that these three enumerated documents can refer to each other by relative URL. Without the SYSTEM ID normalization, these documents can only be opened when exactly the URL is referenced that is also mentioned in the catalog.

Embedding large constant XML in source code

Sometimes one needs to embed XML files into source code. For small files this is no problem at all, just define them as string literals

let s = "<?xml?> ..."

and parse the strings on demand, using the Pxp_types.from_string source. For larger files, the disadvantage of this approach is that the whole document has to be parsed again for every run of the program. There is an efficient way of avoiding that.

The Pxp_codewriter module provides a function Pxp_codewriter.write_document that takes an already parsed XML tree and writes O'Caml code as output that will create the tree again when executed. This can be used as follows:

  • Write a helper application generate that parses the XML file with the required configuration options and that outputs the O'Caml code for this file using Pxp_codewriter
  • In the real program that needs to operate on the XML document reconstruct the document by running the generated code. Use the same configuration options as in generate
There is also Pxp_marshal for marshalling XML trees. The codewriter module uses it.

Using the preprocessor to create XML trees

One way of creating XML trees programmatically is to call the create_* functions in Pxp_document, e.g. Pxp_document.create_element_node. However, this looks ugly, e.g. for creating <x><y>foo</y></x> one ends up with

let tree =
  Pxp_document.create_element_node spec dtd "x" []
let y =
  Pxp_document.create_element_node spec dtd "y" []
let data =
  Pxp_document.create_data_node spec dtd "foo"
# append_node data;
tree # append_node y

It is easier to use the PXP preprocessor, a camlp4 extension of the O'Caml syntax. It simplifies the above code to (line breaks are optional):

  let tree =
    <:pxp_tree<
      <x>
        <y>
          "foo"
    >>

For more about the preprocessor, see Intro_preprocessor.

Namespaces

PXP support namespaces, but

  • this has to be enabled explicitly, and
  • the way of processing namespaces is different from what parsers do that output DOM trees
How to enable namespace processing. Depending on the mode different things have to be done. In any case a namespace manager is required, and it has to be made available to PXP in the config record:

let m = Pxp_dtd.create_namespace_manager()

let config =
  { Pxp_types.default_config
      with enable_namespace_processing = Some m
  }

In event mode, this is already enough. In tree mode, you also need to direct PXP that it uses the special namespace-enabled node classes:

let spec = Pxp_tree_parser.default_namespace_spec

Of course, PXP can also parse namespace directives when namespace processing is off. However, all the namespace-specific node methods do not work like Pxp_document.node.namespace_uri.

Prefix normalization. PXP implements a technique called prefix normalization when processing namespaces. The namespace prefix is the part before the colon in element and attribute names like prefix:localname. The prefix is changed in the document so every namespace is uniquely identified by a prefix. Note that this means that the elements and attributes may be renamed by the parser.

For details how the prefix normalization works, see Intro_namespaces. Namespace processing can also be combined with event-oriented parsing, see Events and namespaces.

Specifying which classes implement nodes - the mysterious spec parameter

For the tree representation PXP defines a set of classes implementing the various node types. These classes, such as element_impl, are all defined in Pxp_document.

It is now possible to instruct PXP to use different classes. In the last section we have already seen an example of this, because for namespace-enabled parsing a different set of node classes is used:

let spec = Pxp_tree_parser.default_namespace_spec

The mysterious spec parameter controls which class it uses for which node type. In the source code of Pxp_tree_parser, we find

let default_spec =
  make_spec_from_mapping
    ~super_root_exemplar:      (new super_root_impl default_extension)
    ~comment_exemplar:         (new comment_impl default_extension)
    ~default_pinstr_exemplar:  (new pinstr_impl default_extension)
    ~data_exemplar:            (new data_impl default_extension)
    ~default_element_exemplar: (new element_impl default_extension)
    ~element_mapping:          (Hashtbl.create 1)
    ()


let default_namespace_spec =
  make_spec_from_mapping
    ~super_root_exemplar:      (new super_root_impl default_extension)
    ~comment_exemplar:         (new comment_impl default_extension)
    ~default_pinstr_exemplar:  (new pinstr_impl default_extension)
    ~data_exemplar:            (new data_impl default_extension)
    ~default_element_exemplar: (new namespace_element_impl default_extension)
    ~element_mapping:          (Hashtbl.create 1)
    ()

The function Pxp_document.make_spec_from_mapping creates a spec from a set of constructors. In the namespace version of spec, the only difference is that a special implementation for element nodes is used.

One can also use this mechanism to let the parser create trees made of customized classes. Note, however, that it is not possible to simply create new classes by inherting from a predefined classes and then adding new methods. The problem is that the typing constraints of PXP do not allow that users add methods directly to node classes. However, there is a special extension mechanism built-in, and one can use it to add new methods indirectly to nodes. This means these methods do not appear directly in the class type of nodes, but in the class type of the node extension. See Intro_extensions for more about this.

What PXP cannot do for you

Although PXP has a long list of features, there are some types of parsing XML it is not designed for:

  • It is not possible to leave entities unresolved in the text. Whenever there is an &entity; or %entity; PXP replaces it with the definition of that entity. It is an error if the entity turns out to be undefined, and parsing is stopped with an exception.
  • It is not possible to figure out notational details of the XML text, such as where CDATA sections are used
  • It is not possible to parse a syntactically wrong document as much as possible, and to return the parseable parts. PXP either parses the document completely, or it fails completely.
Effectively, this makes it hard to use PXP for XML editing, but otherwise does not limit its uses.


pxp-1.2.9/doc/manual/html/ref/type_Intro_getting_started.html0000644000175000017500000000405313055274552023023 0ustar gerdgerd PXP Reference : Intro_getting_started sig  endpxp-1.2.9/doc/manual/html/ref/Intro_advanced.html0000644000175000017500000002451713055274552020347 0ustar gerdgerd PXP Reference : Intro_advanced

Intro_advanced


Advanced topics

How validation and well-formedness modes are implemented

Validation mainly means to check whether the XML tree fulfills a condition, but this is not all. Validation also performs some normalizations, e.g.:

  • Whitespace characters may be removed from the tree where the DTD allows it
  • Default values of attributes are added when the XML text omits them
If there were no modifications of the XML tree, validation could be completely implemented as a property of the DTD object, which is the logical instance for checking such a constraint. However, this is not true, so many checks and normalizations have been implemented within the document tree, and are triggered there. Nevertheless, these checks and normalizations are finally controlled by the DTD, which remains the final controlling instance. This means that validation can be turned off by setting a flag in the DTD object.

An example: If the DTD does not find the declaration of an element, attribute, or notation, it is free to react in two ways. It could immediately signal a validation error. It can also indicate that the requested object is not found, but that the caller should accept that. The caller is here the document tree which tries to trigger this validation check by going to the DTD. If the result of this check is "accept", the tree simply skips all further validation checks. This is how well-formedness mode is implemented.

Now the validation case: If the declaration is found, the document tree takes it, and calls the corresponding validation check routine (often implemented as private methods of the tree nodes). The declaration is often not passed back from the DTD to the node tree in the form as originally parsed, but preprocessed, so that the validation check can run quicker. For elements, the preprocessed declaration is the validation_record, defined in pxp_dtd.ml.

When default values of attributes have to be complemented, the validation_record contains a preprocessed list of attributes. Actually, the node tree takes this list, and looks whether the XML text overrides any of these, and makes the resulting list to the official attribute list of the element node. This kind of dealing with default values is optimized for the case that the are many default values, and overriding occurs only seldom.

The basic well-formedness checks (like proper nesting of tags) are already implemented in the recursive-descent parser module. Neither the document tree nor the DTD has to check any of these.

The mixed mode

Because well-formedness mode is achieved by turning off certain validation checks, it is also possible to run PXP in a mixed mode between both standard modes. Especially, it is possible to check existing declarations, but also to accept missing declarations.

There are two special processing instructions one can include into the DTD part of a document:

  • <?pxp:dtd optional-element-and-notation-declarations?>: This instruction allows to use elements and notation in the XML text without declaration. These elements and notations are then handled as in well-formedness mode. Existing declarations have to be obeyed, however.
  • <?pxp:dtd optional-attribute-declarations elements="e1 e2 ..."?> This instruction allows to use attributes of the mentioned elements e1, e2, etc. without declaration. These attributes are then handled as in well-formedness mode. Existing declarations have to be obeyed, however. Also, attributes of elements not mentioned still need to be declared.
Programmatically, the same effects can also be achieved by setting the allow_arbitrary flags of declaration objects.

Irregular nodes: namespace nodes and attribute nodes

These node types primarily exist because XML standards require them. For example, in XPath it is possible to include attributes into sets of nodes. Of course, this requires that attributes have the same type as other nodes. In order to support these standards better, the node types T_attribute and T_namespace have been added to the tree definition.

Note that these node types are meant "read-only": They provide an alternate view of the properties of the node tree. It does not make sense to modify these nodes, because they are only derived from some original values that would remain unmodified.

In order to get the attribute nodes, just call attributes_as_node (link: Pxp_document.node.attributes_as_nodes). This method takes a snapshot of the current attribute list, turns it into the form of a node list, and returns it. Note that when the original attribute list is modified, the attribute nodes are not notified by this, and remain unchanged.

See Pxp_document.node.attributes_as_nodes for details how the attribute nodes work (e.g. how their value can be retrieved).

Attribute nodes are irregular nodes. They are only returned by this special method, but do not appear in the regular list of children of the element. Note that this corresponds to how XML standards like XPath define attribute nodes.

Namespace nodes are very similar to attribute nodes. They provide an alternate view of the namespace_scope objects, and there is the method namespaces_as_nodes (link: Pxp_document.node.namespaces_as_nodes) that returns these nodes. As attribute nodes, namespace nodes are irregular, and once created, they are not automatically updated when the orginal namespace scope objects are changed.

Links to other documentation

  • Pxp_document.node.attributes_as_nodes
  • Pxp_document.node.namespaces_as_nodes
  • Pxp_document.attribute_impl
  • Pxp_document.namespace_attribute_impl
  • Pxp_document.namespace_impl
  • Pxp_document.attribute_name
  • Pxp_document.attribute_value
  • Pxp_document.attribute_string_value
  • Pxp_document.namespace_normprefix
  • Pxp_document.namespace_display_prefix
  • Pxp_document.namespace_uri
  • Pxp_document.docorder

pxp-1.2.9/doc/manual/html/ref/type_Intro_advanced.html0000644000175000017500000000404413055274552021401 0ustar gerdgerd PXP Reference : Intro_advanced sig  endpxp-1.2.9/doc/manual/html/ref/Intro_preprocessor.html0000644000175000017500000014466713055274552021341 0ustar gerdgerd PXP Reference : Intro_preprocessor

Intro_preprocessor


The PXP Preprocessor

Since PXP-1.1.95, there is a preprocessor as part of the PXP distribution. It allows you to compose XML trees and event lists dynamically, which is very handy to write XML transformations.

To enable the preprocessor, compile your source files as in:

 ocamlfind ocamlc -syntax camlp4o -package pxp-pp,... ... 

The package pxp-pp contains the preprocessor. The -syntax option enables camlp4, on which the preprocessor is based. It is also possible to use it together with the revised syntax, use -syntax camlp4r in this case.

In the toploop, type

ocaml
# #use "topfind";;
# #camlp4o;;
# #require "pxp-pp";;
# #require "pxp";;

The preprocessor defines the following new syntax notations, explained below in detail:

  • <:pxp_charset< CHARSET_DECL >>
  • <:pxp_tree< EXPR >>
  • <:pxp_vtree< EXPR >>
  • <:pxp_evlist< EXPR >>
  • <:pxp_evpull< EXPR >>
  • <:pxp_text< TEXT >>
The basic notation is pxp_tree which creates a tree of PXP document nodes as described in EXPR. pxp_vtree is the variant where the tree is immediately validated - with pxp_tree the tree is not validated, but one can validate it later (e.g. when the whole output tree of the program is built up). pxp_evlist creates a list of PXP events instead of nodes, useful together with the event parser. pxp_evpull is a variation of the latter: Instead of an event list an event generator is created that works like a pull parser.

The pxp_charset notation only configures the character sets to assume. Finally, pxp_text is a notation for string literals.

Creating constant XML with pxp_tree - basic syntax

The following examples are all written for pxp_tree. You can also use one of the other XML composers instead, but see the notes below that explain a few differences.

In order to use pxp_tree, you must define two variables in the environment: spec and dtd:

let spec = Pxp_tree_parser.default_spec
let dtd = Pxp_dtd.create_dtd `Enc_iso88591

These variables are assumed to exist by the generated code. The dtd variable is the DTD object. Note that you need it even in well-formedness mode (validation turned off) - see the explanations in Parsing in well-formedness mode to understand why. The spec variable controls which classes are instantiated as node representation. See Specifying which classes implement nodes - the mysterious spec parameter for the meaning of spec.

Elements, attributes, and data nodes

Now you can create XML trees like in

let book = 
  <:pxp_tree< 
    <book>
      [ <title>[ "The Lord of The Rings" ]
        <author>[ "J.R.R. Tolkien" ]
      ]
  >>

As you can see, the syntax is somehow XML-related but not really XML. (Many ideas are borrowed from CDUCE, by the way.) In particular, there are start tags like <title> but no end tags. Instead, we are using square brackets to denote where the list of the children of the XML element starts and where it ends. Furthermore, character data must be put into double quotes.

You may ask why the well-known XML syntax has been modified for this preprocessor. There are many reasons, and they will become clearer in the following explanations. For now, you can see the advantage that the syntax is less verbose, as you need not to repeat the element names in end tags (I know programmers like brevity). Furthermore, you can exactly control which characters are part of the data nodes without having to make compromises with indentation.

Attributes are written as in XML:

let book = 
  <:pxp_tree< 
    <book id="BOOK_001">
      [ <title lang="en">[ "The Lord of The Rings" ]
        <author>[ "J.R.R. Tolkien" ]
      ]
  >>

An element without children can be written

 <element>[] 

or slightly shorter:

 <element/> 

Processing instructions and comments

You can also create processing instructions and comment nodes:

let list =
  <:pxp_tree<
    <list>
      [ <!>"Now the list of books follows!"
        <?>"formatter_directive" "one book per page"
        book
      ]
 >>

The notation <!> creates a comment node with the following string as contents. The notation <?> for constructing processing instructions needs two strings, first the target, then the value (here, this results in <?formatter_directive one book per page?>).

Look again at the last example: The O'Caml variable book occurs, and it inserts its tree into the list of books. Identifiers without "decoration" just refer to O'Caml variables. We will see more examples below.

Elements with one child

The preprocessor syntax knows a number of shortcuts and variations. First, you can omit the square brackets when an element has exactly one child:

<element><child>"Data inside child"

This is the same as

<element>[ <child>[ "Data inside child" ] ]

Details of data nodes

Second, we already have used a common abbreviation: Strings are automatically converted to data nodes. The "expanded" syntax is

<*>"Data string"

where <*> denotes to construct a data node, and the following string is used as contents. Usually, you can omit <*>, so this is the same as

"Data string"

However, there are a few occasions where the <*> notation is still useful, see below (essentially, it also works like a type annotation: the following subexpression must be a string).

Inside strings, the usual entity references can be used: &lt;, &gt;, &amp;, &quot;, &apos;, and also numeric references work: &#n; where n is a number. Note that &lt;, &gt;, and &apos; are not obligatory, as <, >, and ' can be included directly.

Example: "Double quotes: &quot;". For a newline character, write &#10;.

Operators

The preprocessor knows two operators: ^ concatenates strings, and @ concatenates lists. Examples:

<element>[ "Word1" ^ "Word2" ]
<element>([ <a/> ] @ [ <b/> ])

Parentheses can be used to clarify precedence. For example:

<element>(l1 @ l2)

Without parentheses, the concatenation operator @ would be parsed as

(<element> l1) @ l2

Parentheses may be used in any expression.

Super root

Rarely used, there is also a notation for the "super root" nodes. For uses of this node types, see Choosing the node types to represent.

<^>[ <element> ... ]

Dynamic XML

This section describes how to insert dynamically created content into XML trees.

Let us begin with an example. The task is to convert O'Caml values of type

type book = 
  { title : string;
    author : string;
    isbn : string;
  }

to XML trees like

 
<book id="BOOK_{isbn}">
  <title>{title}</title>
  <author>{author}</title>
</book>

(conventional syntax, with placeholders in {braces}). When b is the book variable, the solution is

let book = 
  let title = b.title
  and author = b.author
  and isbn = b.isbn in
  <:pxp_tree<
    <book id=("BOOK_" ^ isbn)>
      [ <title><*>title
        <author><*>author
      ]
  >>

First, we bind the simple O'Caml variables title, author, and isbn. The reason is that the preprocessor syntax does not allow expressions like b.title directly in the XML tree (but see below for another, often better workaround).

The XML tree contains the O'Caml variables. The id attribute is a concatenation of the fixed prefix BOOK_ and the contents of isbn. The title and author elements contain a data node whose contents are the O'Caml strings title, and author, respectively.

Why <*>? If we just wrote <title>title, the generated code would assume that the title variable is an XML node (of type Pxp_document.node), and not a string. From this point of view, <*> works like a type annotation, as it specialises the type of the following expression.

The (: ... :) notation

Here is an alternate solution:

let book = 
  <:pxp_tree<
    <book id=("BOOK_" ^ (: b.isbn :))>
      [ <title><*>(: b.title :)
        <author><*>(: b.author :)
      ]
  >>

The notation (: ... :) allows you to include arbitrary O'Caml expressions into the tree. In this solution it is no longer necessary to artificially create O'Caml variables for the only purpose of injecting values into trees.

Dynamic names

It is possible to create XML elements with dynamic names: Just put parentheses around the expression. Example:

let name = "book" in
<:pxp_tree< <(name)> ... >>

With the same notation, one can also set attribute names dynamically:

let att_name = "id" in
<:pxp_tree< <book (att_name)=...> ... >>

Dynamic attribute lists

Finally, it is also possible to include complete attribute lists dynamically:

let att_list = [ "id", ("BOOK_" ^ b.isbn) ] in
<:pxp_tree< <book (: att_list :) > ... >>

Here, att_list must be a (string*string) list with the attributes to include.

Typing

Depending on where a variable or O'Caml expression occurs, different types are assumed. Compare the following examples:

<:pxp_tree< <element>x1 >>
<:pxp_tree< <element>[x2] >>
<:pxp_tree< <element><*>x3 >>

As a rule of thumb, the most general type is assumed that would make sense at a certain location. As x1 could be replaced by a list of children, its type is assumed to be a node list. As x2 could be replaced by a single node, its type is assumed to be a node. And x3 is a string, we had this case already.

Character encodings: pxp_charset

As the preprocessor generates code that builds XML trees, it must know two character encodings:

  • Which encoding is used in the source code (in the .ml file)
  • Which encoding is used in the XML representation, i.e. in the O'Caml values representing the XML trees
Both encodings can be set independently. The syntax is:

<:pxp_charset< source="ENC" representation="ENC" >>

where ENC is the name of the selected encoding. The default is ISO-8859-1 for both encodings. For example, to set the representation encoding to UTF-8, use:

<:pxp_charset< representation="UTF-8" >>

The pxp_charset notation is a constant expression that always evaluates to (). (A requirement by camlp4 that looks artificial.)

When you set the representation encoding, it is required that the encoding stored in the DTD object is the same. Remember that we need a DTD object like

let dtd = Pxp_dtd.create_dtd `Enc_iso88591

Of course, we must change this to the representation encoding, too. In our example:

let dtd = Pxp_dtd.create_dtd `Enc_utf8

The preprocessor cannot check this at compile time, and for performance reasons, a runtime check is not generated. So it is up to the programmer that the character encodings are used in a consistent way.

Validated trees: pxp_text, calling validate, and pxp_vtree

In order to validate trees, you need a filled DTD object. In principle, you can create this object by a number of methods. For example, you can parse an external file:

let dtd = Pxp_dtd_parser.parse_dtd_entity config (from_file "sample.dtd")

It is, however, often more convenient to include the DTD literally into the program. This works by

let dtd = Pxp_dtd_parser.parse_dtd_entity config (from_string "...")

As the double quotes are often used inside DTDs, O'Caml string literals are a bit impractical, as they are also delimited by double quotes, and one needs to add backslashes as escape characters. The pxp_text notation is often more readable here:

 <:pxp_text<STRING>> 

is just another way of writing "STRING". In our DTD, we have

let dtd_text =
  <:pxp_text<
    <!ELEMENT book (title,author)>
    <!ATTLIST book id CDATA #REQUIRED>
    <!ELEMENT title (#PCDATA)>
    <!ATTLIST title lang CDATA "en">
    <!ELEMENT author (#PCDATA)>
  >>
let config = default_config
let dtd = Pxp_dtd_parser.parse_dtd_entity config (from_string dtd_text)

Note that pxp_text is not restricted to DTDs, as it can be used for any kind of string.

After we have the DTD, we can validate the trees. One option is to call the Pxp_document.validate function:

let book = 
  <:pxp_tree< 
    <book>
      [ <title>[ "The Lord of The Rings" ]
        <author>[ "J.R.R. Tolkien" ]
      ]
  >>
let () =
  Pxp_document.validate book

(This example is invalid, and validate will throw an exception, as the id attribute is missing.)

Note that it is a misunderstanding that pxp_tree builds XML trees in well-formedness mode. You can create any tree with it, and the fact is that pxp_tree just does not invoke the validator. So if the DTD enforces validation, the tree is validated when the validate function is called. If the DTD is in well-formedness mode, the tree is effectively not validated, even when the validate function is invoked. Btw, the following statements would create a DTD in well-formedness mode:

let dtd = Pxp_dtd.create_dtd `Enc_iso88591
let () = dtd # allow_arbitrary

Validating with pxp_vtree

As an alternative of calling the validate function, one can also use pxp_vtree instead. It immediately validates every XML element it creates. However, "injected" subtrees are not validated, i.e. validation does not proceed recursively to subnodes as the validate function does it.

pxp_vtree has the same syntax as pxp_tree.

Generating events: pxp_evlist and pxp_evpull

As PXP has also an event model to represent XML, the preprocessor can also produce such events. In particular, there are two modes: The pxp_evlist notation outputs lists of events (of type Pxp_types.event list) representing the XML expression. The pxp_evpull notation creates an automaton from which one can "pull" events (like from a pull parser). The automaton has type unit -> Pxp_types.event.

pxp_evlist

Syntactically, these two notations work very much like pxp_tree. For example,

let book = 
  <:pxp_evlist< 
    <book>
      [ <title>[ "The Lord of The Rings" ]
        <author>[ "J.R.R. Tolkien" ]
      ]
  >>

returns this list of events:

E_start_tag ("book", [], None, <obj>);
  E_start_tag ("title", [], None, <obj>);
  E_char_data "The Lord of The Rings"
  E_end_tag ("title", <obj>);
  E_start_tag ("author", [], None, <obj>); 
  E_char_data "J.R.R. Tolkien";
  E_end_tag ("author", <obj>); 
  E_end_tag ("book", <obj>)
]

(Here, <obj> denotes the entity_id object for identifying the containing entity.)

Note that you neither need a dtd variable nor a spec variable in event mode.

There is one important culprit: Both single nodes and lists of nodes are represented by the same type, Pxp_types.event list. That has the consequence that in the following example x1 and x2 have the same type Pxp_types.event list:

<:pxp_evlist< <element>x1 >>
<:pxp_evlist< <element>[x2] >>

In principle, it could be checked at runtime whether x1 and x2 have the right structure. However, this is not done because of performance reasons, and because the generated XML is still well-formed. The typing is just different from pxp_tree which distinguishes between a single node and a node list.

pxp_evpull

As mentioned, pxp_evpull works like a pull parser. After defining

let book = 
  <:pxp_evpull< 
    <book>
      [ <title>[ "The Lord of The Rings" ]
        <author>[ "J.R.R. Tolkien" ]
      ]
  >>

book is a function unit -> Pxp_types.event option. One can call it to pull the events out of it one after the other:

let e1 = book();;       (* = Some(E_start_tag ("book", [], None, <obj>)) *)
let e2 = book();;       (* = Some(E_start_tag ("title", [], None, <obj>)) *)
...

After the last event, book returns None to indicate the end of the event stream.

As for pxp_evlist, it is not possible to distinguish between single nodes and node lists by type. In this example, both x1 and x2 are assumed to have type unit -> Pxp_types.event:

<:pxp_evlist< <element>x1 >>
<:pxp_evlist< <element>[x2] >>

Note that <element>x1 actually means to build a new pull automaton around the existing pull automaton x1: The children of element are retrieved by pulling events from x1 until None is returned.

A consequence of the pull semantics is that once an event is obtained from an automaton, the state of the automaton is modified such that it is not possible to get the same event again. If you need an automaton that can be reset to the beginning, just wrap the pxp_evlist notation into a functional abstraction:

let book_maker() =
  <:pxp_evpull< <book ...> ... >>
let book1 = book_maker()
let book2 = book_maker()

This way, book1 and book2 generate independent event streams.

There is another implication of the nature of the automatons: Subexpressions are lazily evaluated. For example, in

<:pxp_evpull< <element>[ <*> (: get_data_contents() :) ] >>

the call of get_data_contents is performed just before the event for the data node is constructed instead of being done at automaton construction time.

Documents

Note that none of the notations pxp_tree, pxp_vtree, pxp_evlist, or pxp_evpull is able to create documents. They just create what is equivalent to the node tree inside a document, but not the document wrapping.

In the tree case, just put the node tree into a Pxp_document.document:

let book = <:pxp_tree< ... >>
let doc = new Pxp_document.document warner dtd#encoding
doc # init_root book "book"

In the event case, the generated events do not include E_start_doc, E_end_doc, or E_end_of_stream. If required, one has to add these events manually which is quite simple. For pxp_evlist, do something like

let doc =
  E_start_doc("1.0", dtd) ::
  ( <:pxp_evlist< <book>... >> @
    [ E_end_doc("book");
      E_end_of_stream 
    ]
  )

For pxp_evpull, do something like

let doc =
  Pxp_event.concat
    [ Pxp_event.of_list [ E_start_doc("1.0", dtd) ];
      <:pxp_evpull< <book>... >>;
      Pxp_event.of_list [E_end_doc("book"); E_end_of_stream ]
    ]

(See Pxp_event.concat and Pxp_event.of_list.)

Namespaces

By default, the preprocessor does not generate nodes or events that support namespaces. It can, however, be configured to create namespace-aware XML aggregations.

In any case, you need a namespace manager. This is an object that tracks the usage of namespace prefixes in XML nodes. For example, we can create a namespace manager that knows the html prefix:

let mng = new Pxp_dtd.namespace_manager in
mng # add_namespace "html" "http://www.w3.org/1999/xhtml"

(Also see Pxp_dtd.namespace_manager.) Here, we declare that we want to use the html prefix for the internal representation of the XML nodes. This kind of prefix is called normalized prefix, or normprefix for short. It is possible to configure different prefixes for the external representation, i.e. when the XML tree is printed to a file. This other kind of prefix is called display prefix. We will have a look at them later. (For a more detailed discussion of namespaces, see Intro_namespaces.)

Next, we must tell the DTD object that we have a namespace manager:

let dtd = Pxp_dtd.create_dtd `Enc_iso88591
dtd # set_namespace_manager mng

For pxp_evlist and pxp_evpull we are now prepared (note that we need now a dtd variable, as only the DTD object knows the namespace manager). For pxp_tree and pxp_vtree, it is required to use a namespace-aware specification:

let spec = Pxp_tree_parser.default_namespace_spec 

(Normal specifications do not work, you would get "Namespace method not applicable" errors if you tried to use them.)

Using <:autoscope>

The special notation <:autoscope> enables namespace mode in this example:

let list =
  <:pxp_tree<
    <:autoscope>
      <html:ul>
        [ <html:li>"Item1"
          <html:li>"Item2"
        ]
  >>

In particular, <:autoscope> defines a new O'Caml variable for its subexpression: scope. This variable contains the namespace scope object, which contains the namespace declarations for the subexpression. <:autoscope> initialises this variable from the namespace manager such that it contains now a declaration for the html prefix. scope has type Pxp_dtd.namespace_scope.

In general, the namespace scope object contains the prefixes to use for the external representation (as opposed to the namespace manager which defines the prefixes for the internal representation). If the external prefixes can be the same as the internal ones, <:autoscope> is the right directive, as it initalizes the scope object with the prefixes from the namespace manager, so that both views are the same.

Print the tree by

list # display (`Out_channel stdout) `Enc_iso88591

Note that there is a display and a write method. The difference is that display prints the external prefixes (from scope), and that write prints the internal prefixes (from the namespace manager). In this introduction we prefer display.

Using <:scope> in its basic form

Alternatively, we can also create the scope variable manually:

let scope = Pxp_dtd.create_namespace_scope
              ~decl:[ """http://www.w3.org/1999/xhtml" ]
              mng
let list =
  <:pxp_tree<
    <:scope>
      <html:ul>
        [ <html:li>"Item1"
          <html:li>"Item2"
        ]
  >>

Note that we now use <:scope>. In this simple form, this construct just enables namespace mode, and takes the scope variable from the environment.

Furthermore, the namespace scope contains now a different namespace declaration: The display prefix "" is used for HTML. The empty prefix just means to declare a default prefix (by xmlns="URI"). The effect can be seen when the XML tree is printed by calling the display method.

If we had called create_namespace_scope with the decl argument

  ~decl:[ "foo""http://www.w3.org/1999/xhtml" ]

the displayed tree would use the foo prefix, and declare it as xmlns:foo="http://www.w3.org/1999/xhtml".

Using <:scope> to set display prefixes

Here is a third variant of the same example:

let scope = Pxp_dtd.create_namespace_scope mng
let list =
  <:pxp_tree<
    <:scope ("")="http://www.w3.org/1999/xhtml">
      <html:ul>
        [ <html:li>"Item1"
          <html:li>"Item2"
        ]
  >>

The scope is now initially empty. The <:scope> notation is used to extend the scope for the time the subexpression is evaluated.

There is also a notation <:emptyscope> that creates an empty scope object, so one could even write

let list =
  <:pxp_tree<
    <:emptyscope>
      <:scope ("")="http://www.w3.org/1999/xhtml">
        <html:ul>
          [ <html:li>"Item1"
            <html:li>"Item2"
          ]
  >>

The <:scope> notation can be used in any subexpression, and it modifies the display prefix to use in that subexpression. For example, here a different prefix foo is used for the second item:

let list =
  <:pxp_tree<
    <:emptyscope>
      <:scope ("")="http://www.w3.org/1999/xhtml">
        <html:ul>
          [ <html:li>"Item1"
            <:scope foo="http://www.w3.org/1999/xhtml">
               <html:li>"Item2"
          ]
  >>

It is recommended to create the scope variable manually with a reasonable initial declaration, and to use <:scope> to enable namespace processing, and to extend the scope where necessary. The advantage of this approach is that the same scope object can be shared by many XML nodes, so you need less memory.

One tip: To get a namespace scope that is initialised with all prefixes of the namespace manager (as <:autoscope> does it), define

let scope = create_namespace_scope ~decl: mng#as_declaration mng

For event-based processing of XML, the namespace mode works in the same way as described here, there is no difference.
pxp-1.2.9/doc/manual/html/ref/type_Intro_preprocessor.html0000644000175000017500000000405013055274552022357 0ustar gerdgerd PXP Reference : Intro_preprocessor sig  endpxp-1.2.9/doc/manual/html/ref/Example_readme.html0000644000175000017500000022641613055274552020341 0ustar gerdgerd PXP Reference : Example_readme

Example_readme


The readme processor

The task of the readme processor is to convert a document conforming to the XML DTD "readme.dtd" into an HTML document or a text document. This example especially demonstrates how to use node extensions to add custom methods to nodes (see Intro_extensions), and how to use the object-oriented feature of late binding so that every node type behaves differently.

Note that the converter code dates back from 1999. Nowadays I would probably have written it as a purely functional transformer. This task is now left to the reader...

The readme DTD

The motivation for readme was that I often wrote two versions of files such as README and INSTALL explaining aspects of a distributed software archive; one version was ASCII-formatted, the other was written in HTML. Maintaining both versions meant double amount of work, and changes of one version could be forgotten in the other version. To improve this situation I invented the readme DTD which allows me to maintain only one source written as XML document, and to generate both the ASCII and the HTML version from it

In this section, I explain only the DTD. The readme DTD is contained in the PXP distribution together with the two converters to produce ASCII and HTML.

The documents have a simple structure: There are up to three levels of nested sections, paragraphs, item lists, footnotes, hyperlinks, and text emphasis. The outermost element has usually the type readme, it is declared by

<!ELEMENT readme (sect1+)>
<!ATTLIST readme
          title CDATA #REQUIRED>

This means that this element contains one or more sections of the first level (element type sect1), and that the element has a required attribute title containing character data (CDATA). Note that readme elements must not contain text data.

The three levels of sections are declared as follows:

<!ELEMENT sect1 (title,(sect2|p|ul)+)>

<!ELEMENT sect2 (title,(sect3|p|ul)+)>

<!ELEMENT sect3 (title,(p|ul)+)>

Every section has a title element as first subelement. After the title an arbitrary but non-empty sequence of inner sections, paragraphs and item lists follows. Note that the inner sections must belong to the next higher section level; sect3 elements must not contain inner sections because there is no next higher level.

Obviously, all three declarations allow paragraphs (p) and item lists (ul). The definition can be simplified at this point by using a parameter entity:

<!ENTITY % p.like "p|ul">

<!ELEMENT sect1 (title,(sect2|%p.like;)+)>

<!ELEMENT sect2 (title,(sect3|%p.like;)+)>

<!ELEMENT sect3 (title,(%p.like;)+)>

Here, the entity p.like is nothing but a macro abbreviating the same sequence of declarations; if new elements on the same level as p and ul are later added, it is sufficient only to change the entity definition. Note that there are some restrictions on the usage of entities in this context; most important, entities containing a left parenthesis must also contain the corresponding right parenthesis.

Note that the entity p.like is a parameter entity, i.e. the ENTITY declaration contains a percent sign, and the entity is referred to by %p.like;. This kind of entity must be used to abbreviate parts of the DTD; the general entities declared without percent sign and referred to as &amp;name; are not allowed in this context.

The title element specifies the title of the section in which it occurs. The title is given as character data, optionally interspersed with line breaks (br):

<!ELEMENT title (#PCDATA|br)*>

Compared with the title attribute of the readme element, this element allows inner markup (i.e. br) while attribute values do not: It is an error if an attribute value contains the left angle bracket < literally such that it is impossible to include inner elements.

The paragraph element p has a structure similar to title, but it allows more inner elements:

<!ENTITY % text "br|code|em|footnote|a">

<!ELEMENT p (#PCDATA|%text;)*>

Line breaks do not have inner structure, so they are declared as being empty:

<!ELEMENT br EMPTY>

This means that really nothing is allowed within br; you must always write <br></br> or abbreviated <br/>.

Code samples should be marked up by the code tag; emphasized text can be indicated by em:

<!ELEMENT code (#PCDATA)>

<!ELEMENT em (#PCDATA|%text;)*>

That code elements are not allowed to contain further markup while em elements do is a design decision by the author of the DTD.

Unordered lists simply consists of one or more list items, and a list item may contain paragraph-level material:

<!ELEMENT ul (li+)>

<!ELEMENT li (%p.like;)*>

Footnotes are described by the text of the note; this text may contain text-level markup. There is no mechanism to describe the numbering scheme of footnotes, or to specify how footnote references are printed.

<!ELEMENT footnote (#PCDATA|%text;)*>

Hyperlinks are written as in HTML. The anchor tag contains the text describing where the link points to, and the href attribute is the pointer (as URL). There is no way to describe locations of "hash marks". If the link refers to another readme document, the attribute readmeref should be used instead of href. The reason is that the converted document has usually a different system identifier (file name), and the link to a converted document must be converted, too.

<!ELEMENT a (#PCDATA)*>
<!ATTLIST a 
          href      CDATA #IMPLIED
          readmeref CDATA #IMPLIED
>

Note that although it is only sensible to specify one of the two attributes, the DTD has no means to express this restriction.

So far the DTD. Finally, here is a sample document for it:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE readme SYSTEM "readme.dtd">
<readme title="How to use the readme converters">
  <sect1>
    <title>Usage</title>
    <p>
      The <em>readme</em> converter is invoked on the command line by:
    </p>
    <p>
      <code>readme [ -text | -html ] input.xml</code>
    </p>
    <p>
      Here is a list of options:
    </p>
    <ul>
      <li>
        <p>
          <code>-text</code>: 
          specifies that ASCII output should be produced</p>
      </li>
      <li>
        <p>
           <code>-html</code>: 
           specifies that HTML output should be produced</p>
      </li>
    </ul>
    <p>
      The input file must be given on the command line. The converted output is
      printed to <em>stdout</em>.
    </p>
  </sect1>
  <sect1>
    <title>Author</title>
    <p>
      The program has been written by
      <a href="mailto:gerd@gerd-stolpmann.de">Gerd Stolpmann</a>.
    </p>
  </sect1>
</readme>

The readme converter to HTML

The converter from readme documents to HTML documents follows strictly the approach to define one extension class per element type. The generated HTML code is structurally similar to the readme source, because of this most elements can be converted in the following straigh-forward way: Given the input element

<e>content</e>

the conversion text is the concatenation of a computed prefix, the recursively converted content, and a computed suffix.

Only one element type cannot be handled by this scheme: footnote. Footnotes are collected while they are found in the input text, and they are printed after the main text has been converted and printed.

Now we comment to source code of the to_html.ml converter.

Header

open Pxp_types
open Pxp_document
open Pxp_dtd.Entity

Type declarations

class type footnote_printer =
  object
    method footnote_to_html : store_type -> out_channel -> unit
  end

and store_type =
  object
    method alloc_footnote : footnote_printer -> int
    method print_footnotes : out_channel -> unit
  end

For comments see the implementations below.

The class store of type store_type

The store is a container for footnotes. You can add a footnote by invoking alloc_footnote; the argument is an object of the class footnote_printer, the method returns the number of the footnote. The interesting property of a footnote is that it can be converted to HTML, so a footnote_printer is an object with a method footnote_to_html. The class footnote which is defined below has a compatible method footnote_to_html such that objects created from it can be used as footnote_printers.

The other method, print_footnotes 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 footnote_to_html.

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 <- number+1;
      footnotes <- footnotes @ [ number, n ];
      number

    method print_footnotes ch =
      if footnotes <> [] then begin
        output_string ch "<hr align=left noshade=noshade width=\"30%\">\n";
        output_string ch "<dl>\n";
        List.iter
          (fun (_,n) -> 
             n # footnote_to_html (self : #store_type :> store_type) ch)
          footnotes;
        output_string ch "</dl>\n";
      end

  end

The function escape_html

This function converts the characters <, >, &, and " to their HTML representations. For example,

 escape_html "<>" = "&lt;&gt;" 

Other characters are left unchanged.

let escape_html s =
  Str.global_substitute
    (Str.regexp "<\\|>\\|&\\|\"\\|@\\|:")
    (fun s ->
      match Str.matched_string s with
        "<" -> "&lt;"
      | ">" -> "&gt;"
      | "&" -> "&amp;"
      | "\"" -> "&quot;"
      | "@" -> "&#64;"
      | ":" -> "&#58;"
      | _ -> assert false)
    s

Note (of 2009): There is also the Ocamlnet function Netencoding.Html.encode one can use. It has a special XML mode.

The virtual class shared

This virtual class is the abstract superclass of the extension classes shown below. It defines the standard methods clone, node, and set_node, and declares the type of the virtual method to_html. 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 store object which collects the footnotes.

class virtual shared =
  object (self)

    (* --- default_ext --- *)

    val mutable node = (None : shared node option)

    method clone = {< >} 
    method node =
      match node with
          None ->
            assert false
        | Some n -> n
    method set_node n =
      node <- Some n

    (* --- virtual --- *)

    method virtual to_html : store -> out_channel -> unit

  end

For an introduction into extension classes see Intro_extensions.

The class only_data

This class defines to_html such that the character data of the current node is converted to HTML. Note that self is an extension object (of type Pxp_document.extension), self # node is the node object (of type Pxp_document.node), and self # node # data returns the character data of the node (see Pxp_document.node.data).

class only_data =
  object (self)
    inherit shared

    method to_html store ch =
      output_string ch (escape_html (self # node # data))
  end

The class readme

This class converts elements of type readme to HTML. Such an element is (by definition) always the root element of the document. First, the HTML header is printed; the title 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 body tag, and the headline have been printed, the contents of the page are converted by invoking to_html on all children of the current node (which is the root node). Then, the footnotes are appended to this by telling the global store object to print the footnotes. Finally, the end tags of the HTML pages are printed.

class readme =
  object (self)
    inherit shared

    method to_html store ch =
      (* output header *)
      output_string 
        ch "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">";
      output_string
        ch "<!-- WARNING! This is a generated file, do not edit! -->\n";
      let title = 
        match self # node # attribute "title" with
            Value s -> s
          | _ -> assert false
      in
      let html_header =
        try replacement_text
            (self # node # dtd # par_entity "readme:html:header"
        with WF_error _ -> "" in
      let html_trailer =
        try replacement_text
            (self # node # dtd # par_entity "readme:html:trailer")
        with WF_error _ -> "" in
      let html_bgcolor =
        try replacement_text
            (self # node # dtd # par_entity "readme:html:bgcolor")
        with WF_error _ -> "white" in
      let html_textcolor =
        try replacement_text
            (self # node # dtd # par_entity "readme:html:textcolor")
        with WF_error _ -> "" in
      let html_alinkcolor =
        try replacement_text
            (self # node # dtd # par_entity "readme:html:alinkcolor")
        with WF_error _ -> "" in
      let html_vlinkcolor =
        try replacement_text
            (self # node # dtd # par_entity "readme:html:vlinkcolor")
        with WF_error _ -> "" in
      let html_linkcolor =
        try replacement_text 
            (self # node # dtd # par_entity "readme:html:linkcolor")
        with WF_error _ -> "" in
      let html_background =
        try replacement_text
            (self # node # dtd # par_entity "readme:html:background")
        with WF_error _ -> "" in

      output_string ch "<html><header><title>\n";
      output_string ch (escape_html title);
      output_string ch "</title></header>\n";
      output_string ch "<body ";
      List.iter
        (fun (name,value) ->
           if value <> "" 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 ">\n";
      output_string ch html_header;
      output_string ch "<h1>";
      output_string ch (escape_html title);
      output_string ch "</h1>\n";
      (* process main content: *)
      List.iter
        (fun n -> 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 "</html>\n";
  end

This class is an example how to access the value of an attribute: The value is determined by invoking self # node # attribute "title" (see Pxp_document.node.attribute). As this attribute has been declared as CDATA and as being required, the value has always the form Value s where s is the string value of the attribute. Attribute values have type Pxp_types.att_value.

You can also see how entity contents can be accessed. A parameter entity object can be looked up by self # node # dtd # par_entity "name" (see Pxp_dtd.dtd.par_entity), and by invoking Pxp_dtd.Entity.replacement_text the value of the entity is returned after inner parameter and character entities have been processed. Note that you must use Pxp_dtd.dtd.gen_entity instead of par_entity to access general entities.

The classes section, sect1, sect2, and sect3

As the conversion process is very similar, the conversion classes of the three section levels are derived from the more general section 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 the_tag of section by the HTML name of the headline tag.

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 ->
            output_string ch ("<" ^ tag ^ ">\n");
            title_node # extension # to_html store ch;
            output_string ch ("\n</" ^ tag ^ ">");
            List.iter
              (fun n -> n # extension # to_html store ch)
              rest
        | _ ->
            assert false
  end

class sect1 = section "h1"
class sect2 = section "h3"
class sect3 = section "h4"

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 title 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.

Both the title node, and the body nodes are then converted to HTML by calling to_html on them.

The classes map_tag, p, em, ul, and li

Several element types are converted to HTML by simply mapping them to corresponding HTML element types. The class map_tag implements this, and the class argument the_target_tag determines the tag name to map to. The output consists of the start tag, the recursively converted inner elements, and the end tag.

class map_tag the_target_tag =
  object (self)
    inherit shared

    val target_tag = the_target_tag

    method to_html store ch =
      output_string ch ("<" ^ target_tag ^ ">\n");
      List.iter
        (fun n -> n # extension # to_html store ch)
        (self # node # sub_nodes);
      output_string ch ("\n</" ^ target_tag ^ ">");
  end

class p = map_tag "p"
class em = map_tag "b"
class ul = map_tag "ul"
class li = map_tag "li"

The class br

Element of type br are mapped to the same HTML type. Note that HTML forbids the end tag of br.

class br =
  object (self)
    inherit shared

    method to_html store ch =
      output_string ch "<br>\n";
      List.iter
        (fun n -> n # extension # to_html store ch)
        (self # node # sub_nodes);
  end

The class code

The code type is converted to a pre section (preformatted text). As the meaning of tabs is unspecified in HTML, tabs are expanded to spaces.

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 comprehensible: *)
        if i < l then
          match data.[i] with
              '\t' ->
                let n = 8 - (column mod 8) in
                String.make n ' ' ^ preprocess (i+1) (column + n)
            | '\n' ->
                "\n" ^ preprocess (i+1) 0
            | c ->
                String.make 1 c ^ preprocess (i+1) (column + 1)
        else
          ""
      in
      output_string ch "<p><pre>";
      output_string ch (escape_html (preprocess 0 0));
      output_string ch "</pre></p>";
  end

The class a

Hyperlinks, expressed by the a element type, are converted to the HTML a type. If the target of the hyperlink is given by href, the URL of this attribute can be used directly. Alternatively, the target can be given by readmeref in which case the ".html" suffix must be added to the file name.

Note that within a only #PCDATA is allowed, so the contents can be converted directly by applying escape_html to the character data contents.

class a =
  object (self)
    inherit shared

    method to_html store ch =
      output_string ch "<a ";
      let href =
        match self # node # attribute "href" with
            Value v -> escape_html v
          | Valuelist _ -> assert false
          | Implied_value ->
              begin match self # node # attribute "readmeref" with
                  Value v -> escape_html v ^ ".html"
                | Valuelist _ -> assert false
                | Implied_value ->
                    ""
              end
      in
      if href <> "" then
        output_string ch ("href=\""  ^ href ^ "\"");
      output_string ch ">";
      output_string ch (escape_html (self # node # data));
      output_string ch "</a>";
        
  end

The class footnote

The footnote class has two methods: to_html to convert the footnote reference to HTML, and footnote_to_html to convert the footnote text itself.

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.

The footnote must be allocated in the store 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 to_html method stores simply the object itself, such that the footnote_to_html method is invoked on the same object that encountered the footnote.

The to_html method 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 to_html on the sub nodes is done by footnote_to_html

Note that this technique does not work if you make another footnote within a footnote; the second footnote gets allocated but not printed.

class footnote =
  object (self)
    inherit shared

    val mutable footnote_number = 0

    method to_html store ch =
      let number = 
        store # alloc_footnote (self : #shared :> footnote_printer) in
      let foot_anchor = 
        "footnote" ^ string_of_int number in
      let text_anchor =
        "textnote" ^ string_of_int number in
      footnote_number <- number;
      output_string ch ( "<a name=\"" ^ text_anchor ^ "\" href=\"#" ^ 
                         foot_anchor ^ "\">[" ^ string_of_int number ^ 
                         "]</a>" )

    method footnote_to_html store ch =
      (* prerequisite: we are in a definition list <dl>...</dl> *)
      let foot_anchor = 
        "footnote" ^ string_of_int footnote_number in
      let text_anchor =
        "textnote" ^ string_of_int footnote_number in
      output_string ch ("<dt><a name=\"" ^ foot_anchor ^ "\" href=\"#" ^ 
                        text_anchor ^ "\">[" ^ string_of_int footnote_number ^ 
                        "]</a></dt>\n<dd>");
      List.iter
        (fun n -> n # extension # to_html store ch)
        (self # node # sub_nodes);
      output_string ch ("\n</dd>")
 
  end

The specification of the document model

This code sets up the hash table that connects element types with the exemplars of the extension classes that convert the elements to HTML. See How to bind extension classes to element types for comments, and Pxp_document.make_spec_from_alist for the function definition.

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 :> shared));
        "a",      (new element_impl (new a));
      ]
    ()

The readme converter to ASCII

This converter is quite similar to the HTML converter, and not presented here. The source code is part of the PXP source tarball, however.

The main program

open Pxp_types
open Pxp_document
open Pxp_tree_parser

let rec print_error e =
  prerr_endline(string_of_exn e)


let run f a =
  try f a with
      e -> print_error e


let convert_to_html filename =
  let document =
    parse_document_entity
      { default_config with encoding = `Enc_iso88591 }
      (from_file filename)
      To_html.tag_map
  in
  let root = document # root in
  let store = new To_html.store in
  root # extension # to_html store stdout


let convert_to_text filename =
  let document =
    parse_document_entity
      default_config
      (from_file filename)
      To_text.tag_map
  in
  let root = document # root in
  let store = new To_text.store in
  let box = new To_text.box 79 79 in
  root # extension # to_box store box;
  box # output 0 0 stdout


let main() =
  let want_html = ref false in
  let want_text = ref false in
  let filename = ref None in
  Arg.parse
      [ "-html"Arg.Set want_html, 
              "  convert file to html";
        "-text"Arg.Set want_text,
              "  convert file to text";
      ]
      (fun s -> 
         match !filename with
             None -> filename := Some s
           | Some _ ->
               raise (Arg.Bad "Multiple arguments not allowed."))
      "usage: readme [ -text | -html ] input.xml >output";
  let fn =
    match !filename with
        None -> 
          prerr_endline "readme: no input";
          exit 1
      | Some s -> s
  in
  match !want_html, !want_text with
      truefalse ->
        run convert_to_html fn
    | falsetrue ->
        run convert_to_text fn
    | _ ->
        prerr_endline ("readme: Please select exactly one output format")

let () =
  main()


pxp-1.2.9/doc/manual/html/ref/type_Example_readme.html0000644000175000017500000000404413055274552021371 0ustar gerdgerd PXP Reference : Example_readme sig  endpxp-1.2.9/doc/manual/html/ref/index.html0000644000175000017500000001404513055274552016531 0ustar gerdgerd PXP Reference

PXP Reference

PXP is an XML parser for O'Caml. It represents the parsed document either as tree or as stream of events. In tree mode, it is possible to validate the XML document against a DTD.

The acronym PXP means Polymorphic XML Parser. This name reflects the ability to create XML trees with polymorphic type parameters.

Introduction

Reference


Pxp_types
Pxp_document
Pxp_dtd
DTD objects
Pxp_tree_parser
Calling the parser in tree mode
Pxp_ev_parser
Calling the parser in event mode
Pxp_dtd_parser
Calling the parser to read DTDs
Pxp_event
Dealing with events (for pull parsing)
Pxp_codewriter
Generate O'Caml code for creating large constant XML trees
Pxp_marshal
Pxp_reader
Pxp_core_types
This module is for internal use of PXP only.
Pxp_yacc

Index

Authors

PXP has been written by Gerd Stolpmann; it contains contributions by Claudio Sacerdoti Coen. You may copy it as you like, you may use it even for commercial purposes as long as the license conditions are respected, see the file LICENSE coming with the distribution. It allows almost everything.

Thanks also to Alain Frisch and Haruo Hosoya for discussions and bug reports.
pxp-1.2.9/doc/manual/html/ref/index_values.html0000644000175000017500000004277413055274552020122 0ustar gerdgerd PXP Reference : Index of values

Index of values


A
allocate_private_id [Pxp_core_types.S]
Get a new unique private ID

C
close_entities [Pxp_ev_parser]
Closes all entities managed by this entity manager, and frees operating system resources like open files.
concat [Pxp_event]
let p = concat l: The pull functions contained in the list l are concatenated, and a new pull function p is created that pulls from the functions of the list in turn (when one function indicates the end of the events, it is continued with the next function in the list).
create_dtd [Pxp_dtd]
Preferred way of creating a DTD.
create_empty_dtd [Pxp_dtd_parser]
Create an empty DTD.
create_entity_id [Pxp_dtd.Entity]
Create a new abstract entity ID.
create_entity_manager [Pxp_ev_parser]
Creates an entity manager that is initialized with the toplevel entity referenced by the source argument.
create_external_entity [Pxp_dtd.Entity]
Creates a reference to an external entity.
create_internal_entity [Pxp_dtd.Entity]
Creates an internal entity.
create_namespace_manager [Pxp_dtd]
Preferred way of creating a namespace_manager
create_namespace_scope [Pxp_dtd]
Preferred way of creating a namespace_scope
create_ndata_entity [Pxp_dtd.Entity]
Creates an NDATA entity.
create_pull_parser [Pxp_ev_parser]
Invoke the event parser using the pull model.

D
default_extension [Pxp_tree_parser]
A "null" extension; an extension that does not extend the functionality
default_namespace_spec [Pxp_tree_parser]
Specifies that you want to use namespace, but not extensions
default_spec [Pxp_tree_parser]
Specifies that you do not want to use extensions.
display_events [Pxp_event]
Writes the events to the output_stream.
drop_ignorable_whitespace_filter [Pxp_event]
This filter checks whether character data between elements in a "regexp" or "non-PCDATA mixed" content model consists only of whitespace, and, removes these whitespace characters from the event stream. If the check fails, a WF_Error will be raised.

E
entity_id [Pxp_dtd.Entity]
Returns the abstract entity ID
extract [Pxp_event]
let next' = extract e next: Extracts a subexpression from the pull function next prepended by e.
extract_dtd_from_document_entity [Pxp_dtd_parser]
Parses a closed document, i.e.
extract_prefix [Pxp_event]
Returns the prefix in the name, or "" if there is no prefix.

F
from_external_source [Pxp_dtd.Entity]
Creates an external entity that reads from the passed Pxp_types.source

G
get_encoding [Pxp_dtd.Entity]
Return the encoding of the internal representation of the entity
get_full_name [Pxp_dtd.Entity]
The full name includes the ID, too (for diagnostics messages)
get_name [Pxp_dtd.Entity]
Return the name of the entity.
get_notation [Pxp_dtd.Entity]
Returns the notation of NDATA entities, and None for the other entity types
get_resolver_id [Pxp_dtd.Entity]
Returns the resolver ID for external entities, and None for other entities.
get_type [Pxp_dtd.Entity]
Returns the type of the entity.
get_xid [Pxp_dtd.Entity]
Returns the external ID for external and NDATA entities, and None for internal entities

I
iter [Pxp_event]
iter f p: The pull function p is repeatedly called to get a stream of events e.

L
lookup [Pxp_dtd.Entity]
Looks the entity up for an entitiy ID

M
make_probabilistic_pool [Pxp_core_types.S]
A probalistic string pool tries to map strings to pool strings in order to make it more likely that equal strings are stored in the same memory block.

N
namespace_split [Pxp_event]
let (p,l) = namespace_split name: Splits name into the prefix p and the local name l.
norm_cdata_filter [Pxp_event]
This filter removes empty E_char_data events, concatenates adjacent E_char_data events but does not touch any other parts of the event stream.

O
of_list [Pxp_event]
of_list l: Create a pull function fetching the events from l

P
parse_content_entity [Pxp_tree_parser]
Parse a file representing a well-formed fragment of a document.
parse_document_entity [Pxp_tree_parser]
Parse a closed document, and validate the contents of the document against the DTD contained and/or referenced in the document.
parse_dtd_entity [Pxp_dtd_parser]
Parse an entity containing a DTD (external subset), and return this DTD.
parse_wfcontent_entity [Pxp_tree_parser]
Parse a file representing a well-formed fragment of a document.
parse_wfdocument_entity [Pxp_tree_parser]
Parse a closed document, but do not validate it.
pfilter [Pxp_event]
Filters an event stream by a predicate
pool_string [Pxp_core_types.S]
Tries to find the passed string in the pool; if the string is in the pool, the pool string is returned.
process_entity [Pxp_ev_parser]
Parses a document or a document fragment in push mode.
process_expr [Pxp_ev_parser]
This is a special parsing function that corresponds to the entry `Entry_expr, i.e.

R
replacement_text [Pxp_dtd.Entity]
Return the replacement text of the entity.
resolver_id_of_ext_id [Pxp_core_types.S]
The standard way of converting an ext_id into a resolver ID.

S
string_of_event [Pxp_event]
Returns a string representation of events, for debugging
string_of_exn [Pxp_core_types.S]
Converts a PXP exception into a readable string
string_of_warning [Pxp_core_types.S]
Turn the warning into a human-readable message

T
to_list [Pxp_event]
Fetch all events from the pull function, and return the corresponding list of events.

U
unwrap_document [Pxp_event]
This filter removes the document wrapping from the stream (see The wrapping for closed documents for a definition what this is).

W
warn [Pxp_core_types.S]
Send a warning to the symbolic_warnings object, and then to the collect_warnings object.
write [Pxp_core_types.S]
write os s pos len: Writes the string (portion) to the buffer/channel/stream
write_document [Pxp_codewriter]
Writes O'Caml code to the out_channel so that when the code is compiled and executed, a fresh document is created with the same contents as the passed document:
write_events [Pxp_event]
Writes the events to the output_stream.
write_subtree [Pxp_codewriter]
Writes O'Caml code to the out_channel so that when the code is compiled and executed, a fresh tree is created with the same contents as the passed tree:
pxp-1.2.9/doc/manual/html/ref/index_exceptions.html0000644000175000017500000001406313055274552020772 0ustar gerdgerd PXP Reference : Index of exceptions

Index of exceptions


A
At [Pxp_core_types.S]
The string is a description where the exn happened.

C
Character_not_supported [Pxp_core_types.S]

E
Error [Pxp_core_types.S]
Other error

I
ID_not_unique [Pxp_tree_parser]
Used inside Pxp_tree_parser.index to indicate that the same ID is attached to several nodes

M
Method_not_applicable [Pxp_core_types.S]
Indicates that a method has been called that is not applicable for the class.

N
Namespace_error [Pxp_core_types.S]
Violation of a namespace constraint
Namespace_method_not_applicable [Pxp_core_types.S]
Indicates that the called method is a namespace method but that the object does not support namespaces.
Namespace_not_in_scope [Pxp_core_types.S]
The namespace scope does not know the URI
Namespace_not_managed [Pxp_core_types.S]
A namespace URI is used but not declared in the namespace manager.
Namespace_prefix_not_managed [Pxp_core_types.S]
A namespace prefix is used but not declared in the namespace manager.
Not_competent [Pxp_core_types.S]
The resolver cannot open this kind of entity ID
Not_resolvable [Pxp_core_types.S]
While opening the entity, the nested exception occurred

U
Undeclared [Pxp_core_types.S]
Indicates that no declaration is available and because of this every kind of usage is allowed.

V
Validation_error [Pxp_core_types.S]
Violation of a validity constraint

W
WF_error [Pxp_core_types.S]
Violation of a well-formedness constraint
pxp-1.2.9/doc/manual/html/ref/index_types.html0000644000175000017500000002307313055274552017756 0ustar gerdgerd PXP Reference : Index of types

Index of types


A
att_default [Pxp_core_types.S]
Default value of an attribute
att_default [Pxp_core_types.A]
att_type [Pxp_core_types.S]
Attribute declaration in a DTD
att_type [Pxp_core_types.A]
att_value [Pxp_core_types.S]
Enumerates the possible values of an attribute: Value s: The attribute is declared as a non-list type, or the attribute is undeclared; and the attribute is either defined with value "s", or it is missing but has the default value s., [Valuelist [s1;...;sk]]: The attribute is declared as a list type, and the attribute is either defined with value "s1 ... sk" (space-separated words), or it is missing but has the default value "s1 ... sk"., Implied_value: The attribute is declared without default value, and there is no definition for the attribute.
att_value [Pxp_core_types.A]

C
content_model_type [Pxp_core_types.S]
Element declaration in a DTD
content_model_type [Pxp_core_types.A]

D
dtd_id [Pxp_core_types.S]
Identifier for DTDs
dtd_id [Pxp_core_types.A]
dtd_style [Pxp_event]

E
encoding [Pxp_core_types.S]
For the representation of external resources (files etc.) we accept all encodings for character sets which are defined in Netconversion (package netstring).
ext_id [Pxp_core_types.S]
External identifiers are names for documents.
ext_id [Pxp_core_types.A]

F
filter [Pxp_event]
A filter transforms a pull function into another pull function

M
mixed_spec [Pxp_core_types.S]
Children of an element in "mixed"-style declaration
mixed_spec [Pxp_core_types.A]

O
output_stream [Pxp_core_types.S]
Designates an output destination for several printers: `Out_buffer b: Output to buffer b, `Out_channel ch: Output to channel ch, `Out_function f: Output to function f. The function f is used like Pervasives.output_string., `Out_netchannel n: Output to the ocamlnet channel n

P
pool [Pxp_core_types.S]
A pool designates a way to increase string sharing
pool [Pxp_core_types.A]
private_id [Pxp_core_types.S]
A private ID is an opaque identifier
private_id [Pxp_core_types.A]
pull_fn [Pxp_event]

R
regexp_spec [Pxp_core_types.S]
Children of an element in a regexp-style declaration
regexp_spec [Pxp_core_types.A]
rep_encoding [Pxp_core_types.S]
The subset of encoding that may be used for the internal representation of strings.
resolver_id [Pxp_core_types.S]
A resolver ID is a version of external identifiers used during resolving (i.e.
resolver_id [Pxp_core_types.A]

W
warning [Pxp_core_types.S]
Kinds of warnings
pxp-1.2.9/doc/manual/html/ref/index_attributes.html0000644000175000017500000000413313055274552020774 0ustar gerdgerd PXP Reference : Index of class attributes

Index of class attributes

pxp-1.2.9/doc/manual/html/ref/index_methods.html0000644000175000017500000005557113055274552020265 0ustar gerdgerd PXP Reference : Index of class methods

Index of class methods


A
add [Pxp_tree_parser.index]
Add the passed node to the index.
add [Pxp_tree_parser.hash_index]
Add the passed node to the index.
add_attribute [Pxp_dtd.dtd_element]
add_attribute name type default extdecl: add an attribute declaration for an attribute with the given name, type, and default value.
add_element [Pxp_dtd.dtd]
add the given element declaration to this DTD.
add_gen_entity [Pxp_dtd.dtd]
add_gen_entity e extdecl: add the entity e as general entity to this DTD (general entities are those represented by &name;).
add_namespace [Pxp_dtd.namespace_manager]
add_namespace np uri: adds a new namespace to the object.
add_notation [Pxp_dtd.dtd]
add the given notation to this DTD.
add_par_entity [Pxp_dtd.dtd]
add the given entity as parameter entity to this DTD (parameter entities are those represented by %name;).
add_pinstr [Pxp_dtd.dtd]
add the given processing instruction to this DTD.
add_uri [Pxp_dtd.namespace_manager]
add_uri np uri: adds uri as alias URI to the namespace identified by the normprefix np (see above for detailed semantics).
allow_arbitrary [Pxp_dtd.dtd_element]
This method sets the arbitrary_allowed flag for this element.
allow_arbitrary [Pxp_dtd.dtd]
This method sets the arbitrary_allowed flag.
arbitrary_allowed [Pxp_dtd.dtd_element]
Returns whether arbitrary attributes are allowed or not.
arbitrary_allowed [Pxp_dtd.dtd]
Returns whether arbitrary contents are allowed or not.
as_declaration [Pxp_dtd.namespace_manager]
Returns the list of normprefixes and primary URIs.
attribute [Pxp_dtd.dtd_element]
get the type and default value of a declared attribute, or raise Validation_error if the attribute does not exist.
attribute_names [Pxp_dtd.dtd_element]
get the list of all declared attributes
attribute_violates_standalone_declaration [Pxp_dtd.dtd_element]
attribute_violates_standalone_declaration name v: Checks whether the attribute name violates the standalone declaration if it has value v.

C
content_dfa [Pxp_dtd.dtd_element]
return the DFA of the content model if there is a DFA, or None.
content_model [Pxp_dtd.dtd_element]
get the content model of this element declaration, or Unspecified

D
declaration [Pxp_dtd.namespace_scope]
Returns the list of namespace declarations of this scope (i.e.
disallow_arbitrary [Pxp_dtd.dtd_element]
Clears the arbitrary_allowed flag
disallow_arbitrary [Pxp_dtd.dtd]
Clears the arbitrary_allowed flag again
display_prefix_of_normprefix [Pxp_dtd.namespace_scope]
Translates the normalized prefix to the corresponding display prefix as declared in this object or any parent object.
display_prefix_of_uri [Pxp_dtd.namespace_scope]
Translates the URI to the corresponding display prefix as declared in this object or any parent object.

E
effective_declaration [Pxp_dtd.namespace_scope]
Returns the list of namespace declarations of this scope and all parent scopes.
element [Pxp_dtd.dtd]
looks up the element declaration with the given name.
element_names [Pxp_dtd.dtd]
returns the list of the names of all element declarations.
encoding [Pxp_dtd.proc_instruction]
encoding [Pxp_dtd.dtd_notation]
encoding [Pxp_dtd.dtd_element]
Return the encoding of the strings
encoding [Pxp_dtd.dtd]
returns the encoding used for character representation
ext_id [Pxp_dtd.dtd_notation]
externally_declared [Pxp_dtd.dtd_element]
returns whether the element declaration occurs in an external entity.

F
find [Pxp_tree_parser.index]
Finds the node with the passed ID value, or raises Not_found
find [Pxp_tree_parser.hash_index]
Finds the node with the passed ID value, or raises Not_found

G
gen_entity [Pxp_dtd.dtd]
let e, extdecl = obj # gen_entity n: looks up the general entity e with the name n.
gen_entity_names [Pxp_dtd.dtd]
returns the list of all general entity names
get_normprefix [Pxp_dtd.namespace_manager]
Return the normprefix for a URI, or raises Namespace_not_managed.
get_primary_uri [Pxp_dtd.namespace_manager]
Return the primary URI for a normprefix, or raises Namespace_prefix_not_managed.
get_uri_list [Pxp_dtd.namespace_manager]
Return all URIs for a normprefix, or [] if the normprefix is unused.

I
id [Pxp_dtd.dtd]
get the identifier for this DTD.
id_attribute_name [Pxp_dtd.dtd_element]
Returns the name of the attribute with type ID, or None.
idref_attribute_names [Pxp_dtd.dtd_element]
Returns the names of the attributes with type IDREF or IDREFS.
index [Pxp_tree_parser.hash_index]
Returns the hash table mapping IDs to nodes.
iter_namespaces [Pxp_dtd.namespace_manager]
Iterates over all namespaces contained in the object, and calls the passed function for every namespace.

L
lexer_factory [Pxp_dtd.dtd]
Returns a lexer factory for the character encoding
lookup_or_add_namespace [Pxp_dtd.namespace_manager]
lookup_or_add_namespace p uri: first, the method looks up if the namespace for uri does already exist.

N
name [Pxp_dtd.dtd_notation]
name [Pxp_dtd.dtd_element]
returns the name of the declared element
names_of_required_attributes [Pxp_dtd.dtd_element]
get the list of all attributes that are specified as required attributes
namespace_manager [Pxp_dtd.dtd]
For namespace-aware implementations of the node class, this method returns the namespace manager.
namespace_manager [Pxp_dtd.namespace_scope]
Returns the namespace_manager to which this scope object is connected
normprefix_of_display_prefix [Pxp_dtd.namespace_scope]
Translates the display prefix to the corresponding normalized prefix as declared in this object or any parent object.
notation [Pxp_dtd.dtd]
looks up the notation declaration with the given name.
notation_names [Pxp_dtd.dtd]
Returns the list of the names of all added notations

O
only_deterministic_models [Pxp_dtd.dtd]
Succeeds if all regexp content models are deterministic.

P
par_entity [Pxp_dtd.dtd]
looks up the parameter entity with the given name.
par_entity_names [Pxp_dtd.dtd]
returns the list of all parameter entity names
parent_scope [Pxp_dtd.namespace_scope]
Returns the parent object, if any
parse_pxp_option [Pxp_dtd.proc_instruction]
Parses a PI containing a PXP option.
pinstr [Pxp_dtd.dtd]
looks up all processing instructions with the given target.
pinstr_names [Pxp_dtd.dtd]
Returns the list of the names (targets) of all added pinstrs

R
root [Pxp_dtd.dtd]
get the name of the root element if present.

S
set_cm_and_extdecl [Pxp_dtd.dtd_element]
set_cm_and_extdecl cm extdecl: set the content model to cm.
set_id [Pxp_dtd.dtd]
set the identifier.
set_namespace_manager [Pxp_dtd.dtd]
Sets the namespace manager as returned by namespace_manager.
set_root [Pxp_dtd.dtd]
set the name of the root element.
set_standalone_declaration [Pxp_dtd.dtd]
Sets the 'standalone' declaration.
standalone_declaration [Pxp_dtd.dtd]
Whether there is a 'standalone' declaration or not.

T
target [Pxp_dtd.proc_instruction]

U
uri_of_display_prefix [Pxp_dtd.namespace_scope]
Translates the display prefix to the corresponding URI as declared in this object or any parent object.

V
validate [Pxp_dtd.dtd_element]
checks whether this element declaration (i.e.
validate [Pxp_dtd.dtd]
ensures that the DTD is valid.
value [Pxp_dtd.proc_instruction]

W
warn [Pxp_core_types.S.symbolic_warnings]
warn [Pxp_core_types.S.collect_warnings]
write [Pxp_dtd.dtd]
write os enc doctype: Writes the DTD as enc-encoded string to os.
write_ref [Pxp_dtd.dtd]
write_ref os enc: Writes a reference to the DTD as enc-encoded string to os.
pxp-1.2.9/doc/manual/html/ref/index_classes.html0000644000175000017500000001070213055274552020242 0ustar gerdgerd PXP Reference : Index of classes

Index of classes


D
drop_warnings [Pxp_core_types.S]
Drop any warnings
dtd [Pxp_dtd]
DTD objects have two purposes: They are containers for global declarations that apply to the whole XML document. This includes the character set, the standalone declaration, and all declaration that can appear in the "DTD part" of a document., Also, they express formal constraints the document must fulfill such as validity, or (less ambitious) well-formedness. Normally, programmers neither need to create such objects, nor to fill them with data, as the parser already does this.
dtd_element [Pxp_dtd]
A single element declaration that can be added to the DTD object.
dtd_notation [Pxp_dtd]
A single notation declaration that can be added to the DTD object.

H
hash_index [Pxp_tree_parser]
This is a simple implementation of Pxp_tree_parser.index using a hash table.

N
namespace_manager [Pxp_dtd]
This class manages mappings from URIs to normalized prefixes.
namespace_scope_impl [Pxp_dtd]
An implementation of namespace_scope.

P
proc_instruction [Pxp_dtd]
A single processing instruction occuring in DTD scope.
pxp-1.2.9/doc/manual/html/ref/index_class_types.html0000644000175000017500000000630113055274552021136 0ustar gerdgerd PXP Reference : Index of class types

Index of class types


C
collect_warnings [Pxp_core_types.S]
This object is sometimes used for outputting user warnings

I
index [Pxp_tree_parser]
The type of indexes over the ID attributes of the elements.

N
namespace_scope [Pxp_dtd]
The recursive class type namespace_scope represents the original namespace declarations found in the XML text.

S
symbolic_warnings [Pxp_core_types.S]
This object is sometimes used for outputting user warnings
pxp-1.2.9/doc/manual/html/ref/index_modules.html0000644000175000017500000001153213055274552020257 0ustar gerdgerd PXP Reference : Index of modules

Index of modules


A
A [Pxp_core_types]
This is the type anchor

E
Entity [Pxp_dtd]
Useful properties of entities: The following submodule exports all stable properties of the entity classes.
Example_readme

I
I [Pxp_core_types]
An implementation of S.
Intro_advanced
Intro_events
Intro_extensions
Intro_getting_started
Intro_namespaces
Intro_preprocessor
Intro_resolution
Intro_trees

P
Pxp_codewriter
Generate O'Caml code for creating large constant XML trees
Pxp_core_types
This module is for internal use of PXP only.
Pxp_dtd
DTD objects
Pxp_dtd_parser
Calling the parser to read DTDs
Pxp_ev_parser
Calling the parser in event mode
Pxp_event
Dealing with events (for pull parsing)
Pxp_tree_parser
Calling the parser in tree mode

S
StringMap [Pxp_core_types.S]
For maps with string keys
StringMap [Pxp_core_types.A]
pxp-1.2.9/doc/manual/html/ref/index_module_types.html0000644000175000017500000000464513055274552021327 0ustar gerdgerd PXP Reference : Index of module types

Index of module types


S
S [Pxp_core_types]
S is the signature of I, defined below.
pxp-1.2.9/doc/manual/html/pic/0000755000175000017500000000000013055274552014527 5ustar gerdgerdpxp-1.2.9/doc/manual/html/pic/extension_general.gif0000644000175000017500000000371613055274552020736 0ustar gerdgerdGIF87a¡ÿÿÿ¿¿¿,Âþ”©Ëí£œ´Ú‹Ø|ç†âH–æ‰mÁÊ® ÇòL×p´:ûÚþ Aª7L*—LZî4§Ôªµñ„F¯Ü®˜Õ¥ß²ùü ‹d´û O¨×»vüŽçÎé:{þ˜´ÇÇhxø3Hè‚Øè˜ÒÑ! ˆ“ñõ˜ùBÖFY ê§IÚõ™Á1i'Z„Yú4ªpš6J©ÒÊ»›('9‰ ëÛc ¬xy©Ë»\›Ní ¿ïm»š*‚½Yíð;Xì—ªu ;1”€#Ü@„»hÉQçGa"þB):’gÑS?hÚ>i„‹MGh™ l%0 êjÆ›“e©9ñ=”&ÁSΛ'u¾êIï›…Ÿ1š3 5ṤҘ^Œgs¦Ì¨¼DNéЧÓyª¸F•ò´ÞÐrΚ¥(cÓz$½Å}Yö-ܬZ­´J6$Y½°Ð>8éµiÐŒ3±ðML˜™á‘Y·*žÕXécË‘¶9!`¾Ž'kî wôè~«EF:3kÎ$eÃæZóbÚ¹oë4íë¦@ж}/‹ÛmØbh_gÑñ…µ(‹_}Ž-zÕ´åb7ú´Vwn­¿K®º”­uóðlÕ…1žýÎ¥ñ壦îܾþl—þ÷ûZ}ÿG~úÉww`ƒ a„* r êÀ„JXÞ…Ï=¸aˆ è!x"ž8b‰¢È"‰*ò“!‹-¾È^Œ2žè"ÐÝ(cŽ:Çã>þXX= ›FŠ8$’¤(¹ä†M:™ ”LZâ”T"‚¥† θ¥Y]Nh㘆)fš¹&š¸©9â‘nž…"²©àœ"TxžFjéD…Â'( MÕaè ~™( )õaè£<*i ^±(šA„Ò1e§žÞ‘©œpˆ:j9‹äà¨Dy”Z'©íäˆ*#œ´)§Qz)+®ªúJB­–ââ®)žZþ­#[ȲÉ*ëZƦ˜k'ϦŠÊµõ1;ì&ê«]ÜB›ÆµØNgnµDÄô'cgŒÛ,éîih éi_ÀK.ºóÊ[¯ºÓ¡s¥?ïlí¿å"l†=…:Ü0à k›°Â^È„±¸gkq õÚKÅV"ï»±Çû{r–­lE$%›üìxüö2*6+Qè$)£œl|3 \ÝÍ)4¡¼ÛRL/Ò˜®›ÑìÄ,ÔÎJÝr'V'b’=ÿ:+×]/}5ÓF«â¥Â¬‹Ü-]ØbŸ°2ªq÷Ϊ­š­r°z—sišÍZöŽ'vW½÷²‰WXûäú×ÛªëIüþ·W¿!¨+@´ŠA]³úµ-w|; T€æ®îUÄ8«`Câ7´}Qp lcßÃ?Ï ÐƒÍðݧP-˜$Ï'Œ ô^øôÍi}kdȽýQÆi8$”oÀG½æ…P ÌËŸóTvÂ}Mo`#섈ÜÁ*IÔ þ‰ ¸CÄMÑ>Þ»b÷2F¾*ÞP‰,Yâ¸êæb>T_-²,µqꌧbNs¤·§ß1QEͳ] é3ÅŽÐm@_ºÓCÂUF;YȉjP™zCžF.äãÓ’ŸÜ‚À"ÖÉ/R1 ©®Ç;ê}šBË"7WJPjRH˜„$æÚµ¥&NdI*cKL&J)ä¥hø7_N²|ÁÑJ'mb»sxÅäif_:¹Ì]îJ’XW^®^'1Ì2¿éLp3œý˜VžºgÎò¥SùeFŠöJ"3—â hÌy,æáóœúÄçÛ¹µP r1e=‹9‹}ò>û¤”Bþñ·MeFtœåæ5'ãZ"V8êgC=êÏÿIt˜ŽŒ¤T@2ÏdN²2¿Ä—BóÌ—ºî¥0å"MZŽ›Î”¦t¼¡NÊS ÊT}?uTQc:Ôýpô“Áº)N÷äÔ§~g©`Ê©SiÕžŠ+«H ª®®ªT®~õ¨M+†Ä:Ö¤Z•¬ò¡jG»úP£²µFs]V]¡êÕ°æ5­•«ZϺ׵ÆÕ¯ƒ]Qa »NOV¯}jHÛX¢>¤ÖÄædäÖšBvšÊKì…2+UÇþ‰|žýìR©YÎ%áï´Zý¬öZŽ–HÅÂQ/yÛµ–Kµ]jéƒ%,1¸¿ý!01®u\ñrˆÌm®sŸ ÝèJwºÔ­®u¯‹Ýìjw»Üí®w¿ ÞðŠw¼ä-¯yÏ‹Þôªw½ìm¯{ßËÜÉY¾`åâ.G_<£$tá/XLòN‘س?ù4MZÌe*Á¸Dð, làÆXt¢§¤„'zá CX„,%iDmIÄಖÂÝpZì{a‹sáÚm˜N¬ág4œÝ”1i6´‘.Ò%*¤$b¸éããxÈB(;pxp-1.2.9/doc/manual/html/pic/node_add.gif0000644000175000017500000001002513055274552016751 0ustar gerdgerdGIF87aH¯¡ÿÿÿ¿¿¿,H¯þ Ž©Ëí£œ´Ú‹³Þœ…†¢Ñ•扦êʲã ÇòL×öçúÎ÷þïÜ„À¢ñˆL*—Ìä¡ J§Ôê’XÃZ·Ü®÷ |‚Çä²™«¥Ïì¶ûMÃçôúyÃÛ÷ü¾Sï(8˜5Dxˆ˜"§Øè¸8ùHYéÅh™©‰f¸éù… :Jú3¹Xšªª#ºêúŠjs +iÐ6‹ƒ‹ØJÛ[ª«ë+Vàîß_=úYò#çFþÎJ_Ÿiì`€®…ÂßôøÞ˜ÈGrÉ%†Z‚,È a “aƒM@˜O‡¸‰}`(bg$‘¢€L€h^‹.®˜‰‰È8#Càxà‹¢Æ£†:Zbc(âøã*Gʸ!Œc¤Cîg¡jQö8¥Wª¨„“`,‰d–ÚT9Ñ–XŠ)‰™‡]‘ä‡j®‰æ.dùf›£€æƒà©áj¥ §œ™Xß`ލ5uvig—.W ¢‰úQä|ºF_¤¬5ÊÌ›p"áå%  è¤Îi騚njª8ž&j—ö¹jŽ­B‚*³bZ«­qî*"¬œ‚úh¦»{þk…ƒÞX¨±…¶ l°zþ׬Ÿ½†l²AäŠUµÀ‘ʪ©Ñf(ì…¯’ ­‘ܺ1î¨è&Ú®åR»(xé²».»õ’ À¯çNK¯™kvooǼåÀýŠï³SºïuÙ Õ²Ì \ÓÄ{FÜŸÆa¨9Å_Tª+ÈqxL(ÆŒžÚpt¸&²‚ùöÓ²t7LbÍ¥>Œ« ³‚r²$cãj”Æœ¦ŒÎá®|â"FÇ\ÌÑXl©ÓAÚõ=OûØtO3IÖA3\ö—-å Ôl·Í7ÜÉ]t‡ŒÈä÷ØE ]Æ@ݤø wÄiþc˱>G'9U]Ëjˆû°¶âZQMtBŽ“+Òç=„~¡“œû*8`Yí^N¸ÝwyÁŒëý¯Ûî˜KØîêëÃs÷ÁÀ·õ'O)I¾CîÚî~‰Tcèüí &ŸÒù)@«ôÉnýÉ}: …¬‹‘oøÒvœ7d%±>»Å$~÷Ü·?ÙÁ·áÖ7®±¯:¤3ÛüfýtçCû»ž)tÕ@[¸x»bï?ä'AFE°n á%F(bØÅ}ÿ£ßÂ4=:¨<¡ÁÿZˆ„úð~{1 ‹3º^0L8û¨G…Oá€6¼a ·×¸XynùSÖþ}ÓÄŠ] Ud‹!Cå=4Ùê"qxx*FP‰c¬˜ê†¸Ä"¾Pd_œkØF rA‡\”âXÔh°6º1޵ñÓUÇ…ñw ¡ÇŒ8¡ÅQ&ŠÙbbÀÆAK"…‚báÈ)FB¦ðKò^192*‚Ryäqbòøˆ¦D’-‡ü^+µØÈ$ÎQ„’Ôœ Ô¸Uúï—£¤$´òö"vO“®4C-MaÊeJ̇üÀ3ó#JGÞÁŒÈ@æ,™é>hè1ŠÃ‰¦4sÞ3œÑSæ“v9%Yög—.±`•®iHxírã¤æ'…ÉÎvt Ô‘<{‰ÎAQ£ŸgxÛ>þûãÎT~å\g3!Ooh Ã¤Cóq4sb3›/A™ç@eQ\&tdú¼‡FJÒŽn‹£h€¥aSäU/¥ )O'ÊÉ`‹4•i|Òd|öÅŠ+µ73™S£µ¨;¬ÈAypÒŒ“†Ae^¤—Õ[L,¬(m*·ú¥–ºâªAtÕ7ѪMByu£?¥ÂSUÚ$³ž®`Pê^ŠÕˆú”¯ìj ÐVÁJô%"ðk`£ªRÂ’’#€m+d¥:ØË:è–Ë$+HKUóñ¢¡¢Z™QYP”Mð m]}˜;¹`4YÓëGëZÛ¶Á¦lKm(u¿7NõµDy‚C þ!{nA‘óQ8œ30ÃÊ⮕ôäöšËÚn”•¸©<ÜJ8‹T.·‡#¯p3+Ùus¨aø sÏûXîVµnlI®|É@D2½-¹¯x‹ß~U¿Ì. \ L·¼³u®xyÉß¹j‚Ò¨u;¶<ò"8cþµëÌ×aæ÷ÁƒktÚS±j9I1†7Ì<ÏΧ¾?9‰Œ?+À ç‚ÄXõH…Aç⸭¸ÇʱŽ%vbK™’<ëÃî|rì3§Â7þ["Øú‘ÒZ˜BAùñ€m,A隱ʊ<2þK¹ cEÀå)㔩¬åÍv¤¶qNŽÁë`‘Y?õý„Ô5þä[fBxŽž(¾[èîV9bƦôÜÞGçïAà‚4…—”è^X’¾kì#>Ä|zS–.)L*]ê¶·X>b5Vâjˆ=Š|ž‰¼Ü4ëW+*×äL °¨›¸øÎQäâO¼€½¸v!Û²PZ±ÿðìíE›”‹9vƒ,ܵHÛ+S·;8Ìo»cãNv¹wx’mÿp¡h3E»Y8}Ñ­tá¶”æín|Ãûܨ™fÞíOV\-ßñ8ÀCtðjÊ&ß·¾£×ð~Ó÷ß ß,Ä#~ñŠïãw¸Rëè¶3uÏãÂÞš†ÃCq«zä$Ï8Ç7nòŽ·\¨›–ÇÏ\®rþ-Í<¿(·ùÎ-Îp•ýæ,ÿ¹ƒ„®ðfÇé0yÓ_þ‡AÎ铺їÎô,˜,F[Oú^SNtYp ëYµÔ§Nõ•?=í¶îºØÝžVõl\RòºÛ^v¼‡]ëp¿®Hg5÷kÒêW×{áÁ~x5Ë5µ3OÞB¾´·çñl´ÒT»>à|ï»áyÏËêQÙ<ÍëMùÊû|ò«ß»Ùû¼ëÚ•Þa@—<ëCû³‰¾¦‹ÿõé®óÝïã_¶w}²zûÜ»ñÅ%<èuŸ{ÚEHò2÷¨yI}þù±>‘ÿ }¹[ߘÅ7~ë§?·±ó¾X·¶{d“õóþ›øÄÇðÙÓ¿x^W½üªÇýüéï}v¥*í7Cµ–}‘|Ø}è·`…-ÆãXv¶vý~Ü·€H}â×W6XwÇ€(r–gÇBwÚ'+Á ‚Ç•€ÿç ™w‚°#+§~Û—sè‚û€7j´·ü—ƒ/ð÷p,¥€`TkøƒLHX„†–jN…N¥BI(}M¸‚Ttƒœ°„[Xt;…C(h8÷„:å|d8†GHvMÈE](3_ˆ…¨†Yx†ÓUrbˆ†iȆmX…òWpqç†eVs:ø‡†X‡vˆÃ…U ˆ_|ømw‡k(-‘}çM—˜‡‰Hþ‰¨c‰z¸‡è‰xˆFè.Õy˜¸„hÇo’¸ˆB8l˜‘Š8抑¸‰¶HНXƒ¬X‰Õ…z~ˆ‹µŒaØŠH…±8^a£4õ¤‹xŠŽ§ˆÏè‹ÀçŒèp½xÈø{Ëh?Ùk“m9ªxá8Bòd9å4ŽâŽ4ƒ.ódA0.U,¸jÒK1ŠËVˆòU(nøhn©p£*iÓ|àÈ|/òNÐÛx:™w¿§tØ&~ Ô,)‘ôö.è‘=ÄyòØ<™ÆbrÇg’$ ZicÍ[¦“¿ÈƒáSJ#9…ßG“º2‘ô…=,‘E)˜]Ô4*¹‹èþâkHóùu"9”7éwƒs@1&ðe…0h»aYTiWlf•W0IñÕ?AØ•½Qd#ÅcJØc¹‹faX™Nji0Z™ܱSi —+i”E—@y—1Ùsƒå”ZE}Y”$ÄT E„iŒof=wƒeŠ™YÆ• âet¤^bŒ8˜¹_Œ‰AŽY™#[˜™™m¹™œ9buYM‰š”I„hf`yš­ygg‰^&š÷ÂDUšç$“´éw¶YBž©?À¹IÂù@l‰—³iœ(Ù›-œLÓœÚÉZ܉deiG¿ ž{æã‰yžìaþ¢Ež°™í¹câcñ eôÉTï)Zö¹”h¦ŸË2,]F™Z’z]Ž„˜yw Ÿª)hÊE”ßé ðI“ƒ”?HA±Å•´©¡Š¡”¦¡'‰‡Ú‚Ò¢8‚¦É &ê‘Y ÑHjíå¢51ŠUÉ/Õ7œæi ÿè1°FõY£**!:Œ8¤2z‘£×ކ–¤t¤¸¦n²Ù¢=ÚŒJ°|Gz2OzŒ7šÅh€OrÈâ6 •›93‰w¥ï× ª‰Å¦Y¡XJ ØTgêEƒ(Œ}HIêmò§ÌöŸí¨1h§i¢"¨s(Hxê `(¥Zè¨ ‡ ©…:þ–ÊŽÈ1£©Ä6‡ —Ÿ ªvÚ©¢YY©5©I³ª·ƒ§ª;©J,¯z§.º‚¹§¥(§nJ«ìª˜j•¹ª«¢È§Y†«žR¬Õ¸¦·š¨ÊÚ$Ð:9Éj«f8‰¢š©ÒÚÕŠ¨š«?ò­#5ŸÍ®›ª­Ê!ÜJŒ±*¬Ãª®Æ ¦_5¤¤Z«ÁºŠú®ðŠ[Z£ôZ¯—z¯­é¯Àjªèš®‡º«Çʦ K¨ùʬZZ~êˆ ¯ƒêŸT¨M¥¼Ú«Vª§ëª° ¡}ù¦†§²JGq «k±éé®*k­ûZ¢ˉިâZ¥ú9¦Nű¾D³!«ª@ý+² CÜȳÍÚ\š£2‹<ëH¥-KŸ5c¤M 4JË‹K**^*¨m:§Ê6”7[µV»´XKJ¹µCë­Ö˜Jf[œb‹ &V‘2¡h{¨ù¡¥‡²×Cj±e°C{ö3·9K´„ù·q» ë¶~Û®‰+ŒkP‹ë¸š¹+‚­“»}k¹o5®™û ˜Ë¹te—Ÿ{'ž+ºû)¸¥;º¨›4«ºªAº­Ë¢P »5òº³‹³²k»›»Jº»¾û ½ ¼´8¼ëºÅ» µ‹¼tËŸËû»Î« • ½Ä;½½°Õ;8- ½Û˽Ýë½ß» ¾ãK¾åk¾ç[;pxp-1.2.9/doc/manual/html/pic/node_clone.gif0000644000175000017500000000716613055274552017335 0ustar gerdgerdGIF87a¿¡ÿÿÿ¿¿¿,¿þ”©Ëí£œ´Ú‹³Þ¼û†âH6À‰¦êʶî ÇòL×öçúÎ÷þ ‡Äâ«„L*—̦ó J§ õŠÍj·Ü®÷+²‚Çä²ùŒN“Åê¶û ËÕì¹ýŽÏë÷’:ÿ(8ˆåGxˆ˜¨¸ø`Èø)ç8iy‰™U©Ùéù ZÁJZjª9zªºÊ:˜Ú +ëö:k{‹›UK·›;‹â‘rÖ;¦2€¬|{œ<¼,0 üU|¬½½  À-îì{B}Ž^}í w2þŽýéþ>În ®OŸÔ¯[/à=y Â„7@–¹} ÕmùwÅàAx N¬q^Ãþu D#ñ¢½ŠBŠäöñT>Ž SJɸé¤@’˜LÊìÆj%Ë–ÛØ¼©Í%ÍE?êIçN†HÀ|RÔhÓ¡„¢šIéÒ}X•¸¼¾ÚµYjß~‰ôøîþí'.ß]L©gFX)ðןx’¥`€¦“Üuçy *¸ …>xN„LH!h8]øcàÉÆá|…x؉¡¢,Öä"E*¥ØaOÄP#Je`õ[Œ“°Ó㈪`—ÞŠ;PäQB¤<59ct8â6…|Då“L> 0ˆ1¥0Öˆ†@—­ ©V[UV!£‹V¼éA™<297tÖ§Tz®Éfv{R e\ùÖ—k¤iM]Ž­€&£<&Êã y(–zq(£¼Ýó'Œi.W¨uúå§’ž•’srQèv’¦Ä JdŽj©(`‚æ(dæJÔ¬qþ$f4xKþɰ†kžÈ:ª±&@Ú*žÒ’HK´M± £µÏúT-£g*êæ5ä^Kª0Þb›íî2Ш•´*”õnÚ–µè¦{n´×~Ënò¾ o¸ÝþûI™l)¬#¬­šZp¿Ú†0Hï{ð¼üê °—w:º.¾u ä½áB\±¨Õ–,ñÄÿrú¾¬q¾ÛÛ²¿ïH盄5‹³Îàj‚Ж ¼ó˜ïÒL±ÍF+í.R\fÛs ’±ºÇýô<ÿEdÓT­µ¾2G 5ÁWMÂÕ#w͵´ÛÂ]ØÊÈË´Øo›}¶ÜCó™ÚÊŽÉ+džױ+³Ïœ9.©ÅÌøâ¼~þxsßa§t°¸þL7_yc v̾Iæ[§=¥h Žôå ·ê­/-kåe#Í/éšëÞ7ìNåM+å•>ž»éNA9ù͸£ë:¦ÌzÛ(îwÔç™5öç2µ×—m¼WL/¼ô:>ÊSÿú볯nðÜ£·?präßmûüŸg™¿(ý{>¶ìAë{j£Ù¯”$ű¡p˜ê•˜è@q™.q U#ˆ¿ÿÍwÅÛ_n48@êÇ€ ü›ù„æAÖ)R'Ä\øø–B°°w/lÛ˺'°ž¯0kAîW>f-†úÑ¡ö„Ø¢—Ð34Ä ÖЉŠÀáþ ›²Í~F„aʎן!±rOl[Á7Å,~+Š:#ó¾È—%f°…Ê£ŒÁ×1-‚îŠt¬#ýqÇ⥑ŠUÁbdžgYQ9w\äádHr.’à¢dïzˆ,GÖ®~|då(E·q²’£db)9@66 ìym<¥'ňH3-0‡®\Ô¾öľruÚ-kùÊêY^¬ åˆ7(M&±EªÄÏ,Ëcêq†ð/¡9È]s—Ñ4TÏ —ÈgB³Œþ¸Þ¥À©Fq¶²›kØ&7Ù‰fªsKÅ\'<çÀ­¹“žó "9uÕO«5-“>Cg:‡éÅ*úP.U#Bþ x‡ÇkŸËÔ‹D­–Kʹ.GÀCC Ìc©ˆ E1jCeöò¡_Ú(e\àQ•z“¥Ã»çCdÎåU¤!EKG˜ÊÁ¸Ì(@º˜@:“¦f²¨R±ù¡èA¢£oÀ©^¼YÏ¡R©‰L§Q-¡“bPŸ ] 2=§±&ÏM·Úêùˆ‡Jí((kåçqÌ PmÍÕÓaYaT+çÀµ ÒàÇ`ó ½ÀÖÕ¤õ±ÍaÅ'.ô,–PAzŽ^ì×Ôñ†¬ùü¡eÃ`ŸÊjÖ5/ méxdÚx Œ.aeL(˜®ò¯ñKk·RÙTù*ÊcoU{79ÕI@QІŸ8þK­BˆÅPÄÕÌœŽ«ŸæBEºQýhìÇ!û]×?BÍ g°›]ål×)šhy«{79GÎUï{º›÷ Œ½Û‘“¬Fßèž7¸éµï£®¤)aØ÷¾Ü¥­~üß+M¦I­‚½`°å…ÁÉ€܈7Ø«F€Áö’»[8ÂÖñeIÜ OxÂÞ°0.Œa´¸ ŽAK;Ë ƒ Æ`k±‹QÉã«XW„òñMcÛÙÇUª± fà,ÙQIŽ1©˜œÅ*7YË”]òŒ ÅåÚä;;x~7‡ýݨi§ûËŸŽ8°±spŽÃÛÕof¸É2Œpx™¼Òü–Æ}¨q½´7r2~êåšüߤÓç¯Ë)µÉL…õ-j—%î9…ý_jŸ°¬uJZúªýi0reTjÉß ¡þ.-›E¥û-óøSÓ™1¸rìXtu.ÑXRRCgÅ Xg ßÁW|$.ÇT7&“%>Ë¢€Œåq8t8Gzƒn €$5‚ò}ŒÔ/ù”:dÖW„ÃvYr‚«”TÊ6DÙ4óW74XGÝ'%<È0xdƒAƒYÑp·„Á4-?AãR1„Dx:Fx„H'K"LR8…/åGC4Gt…T(ƒ^¢S&tA¢Ñ‚íò…LX3`èrb8†¨s†lh9£dA< qˆF1#%‡!Ać}{Æ`7˜…‚xU]hJ6Õ‡xhBŒøFˆè‡õU’˜„„H‰Oe‰[¢þ‰Vµ‰:¸79Ÿ@4U‰¤ŠüÃTžˆŠa°ŠšH…Ž8?‡Q­F=EH¶ømœ‹;¤‹E4·ô‹UÈ‹ÁȊÈMaÕ‹¯$‹d䊸ˆŒ³È"§HŠÍ˜PŸŒÑ˜‹dµøŒ¢¨Î˜ˆâèIßxŒ†h‡ ’Ž‹H‹Þ˜Bí¸ˆëØòxHô¨Ÿƒ2¸´ŒÃ¸ïôŽpäˆgøø““LÙX1)VØhŽ¿T^Ñ)Ã\åi‹R%‘ É.xøQÌ„‘¨‘~’ã‘èWo8Ž.¨’9Õ 9>ÔhW-¹’Ž#“½d‘’‡Dõ;YU“„ÑÓⓟ¸“þÉi9ù“k¸FC¹‰èèV/™‘OY’r†‹ƒoõ€±…å„•YŠT€[ÙU‘e€YÙƒ’%–„eJñ‚0¹–qZa‚ rÔT)üL@ó[¥ÕnÕˆ[yô—H+—¿ó|M©iÉFX–ÇŒ¸$|¿Ç˜‚˜˜‰ÁùEZ2™9a¯‹œWwœé–›g™¬W}l˜™” ™¥y™>wa7šçØšòÆu«ù™±™y¶y™vWr¸ÉŽ[vv²É› ©›†÷š$#§©"¤é™„œR›Á"oÀù›9»YÆ™i×Iœ ™›M×qÐ Ò ž¨·œß9œÛ–ž½©œç©žþÙI‘Üy›ðÉž:GŸ wŸØÒœÉIù9žÛYž»WœÂ P"ŸÚÙžÞùžâI•º ³i’ºž³çŸÆé 8W¡P$¡ f EJ¡ Êä9¡ø ¡Þ衲ơžqœ%¢ Šž'ŠîI•¾)¢N·¢ìè¢&: õ™ ©—š´'˜7úv4Z£ˆ×£ó)¤Cj¤Jªš¡ùœOú£}išMê¤@ AÊ{•¹¤`xšæÕ¥P*šç7]‘‰ˆ“©HRJ‘–B˜GMI”½…IpÚ˜Á‡—›à™§Y²§yIPÁ––¨z(™èX²XXeé•Câ[Ú“„*’m™ŽÚ‘‹š”—z]ƒ˜ª©uº©J›ž ª•ª£z¤¤jªÿyª©Ê¢–ªª­Ê ® «$a–±J«ÁªµŠ«7•«»Š·Ê«¿Ê|À*¬Gâ«Ãj¬Etɪ¬ËʬÍê¬Ï ­Ñ*­B ;pxp-1.2.9/doc/manual/html/pic/node_delete.gif0000644000175000017500000000615013055274552017467 0ustar gerdgerdGIF87a¿¡ÿÿÿ¿¿¿,¿þ”©Ëí£œ´Ú‹³Þ¼û†âH6À‰¦êʶî ÇòL×öçúÎ÷þ ‡Äâ«„L*—̦ó J§ õŠÍj·Ü®÷+²‚Çä²ùŒN“Åê¶û ËÕì¹ýŽÏë÷’:ÿ(8ˆåGxˆ˜¨¸ø`Èø)ç8iy‰™U©Ùéù ZÁJZjª9zªºÊ:˜Ú +ëö:k{‹›UK·›;‹â‘rÖ;¦2€¬|{œ<¼,0 üU|¬½½  À-îì{B}Ž^}í w2þŽýéþ>În ®OŸÔ¯[/à=y Â„7@–¹} ÕmùwÅàAx N¬q^Ãþu D#ñ¢½ŠBŠäöñT>Ž SJɸé¤@’˜LÊìÆj%Ë–ÛØ¼©Í%ÍE?êIçN†HÀ|RÔhÓ¡„¢šIéÒ}X•þC«â{"k¹Û§í7s„¿'8ÄŸ3îá¢Pž8ã›—avÉ»Méã9‡Œ·é/užçêU…>¸îk—Î{#.ìûÙG®ô圢lvåxë}æèUK¿dñ¢[OúÖÁÃÉëµØO¬wëª-;íóZm;çÛ{þ}õíýÔ¦O¤ØðG-LØãv»¸å¬­3­ÐkÀ[_îž:êÁ/~a0ýê—:8 ¼[6Aö½oš“S£¾ ¬{ Ûà2ö@Ÿ!0o"”  1sªžÎn׫`Ϥ¶B æÐ}6,á OÃÞ g,Úoø3üÕÎBôaåô¦â'qöáþã"Cíµ°Z;Ó µ¦,öÁyλßÖĵ}ñlRäØÁ=1挙sâ3ö¸5°‹´ðÖÚÈ›(õ¢c½÷F9 ’A†¸"É©›¦}I€… äâr3 I†ª”q§‡îI‰M Ô™ŠÁfáþ¶PÿIgž éŸ@¹·ÎB> gMY# ÅçT±¡Øé 1Ö gpm ±”ƒTºÒ†¢4AAY¤S¤Á›²3sæù LÄ4½$g—D‰(꥽¡¨ÃyÉuT¨Ÿ^F0¨©Ï|ˆz2ºuœm¡ËEß (­Þt+ó ”„àP±Èé0¡ÓU¾JJ‚nM­èŒ†TÊdVÄÄ­‰é‡L“×4pkK“¹™ÂºŠ°^é_{ºiI7šêd'ÊU¨\v©!Js*ûXÈ"NEõ¬ŠhÔ×Ò*Ö°&åjÛÑÙ]¢¶±P"’(JkZQШCöÂí.0ƒV/¾åìk…þ:[Þì6/®Ämnû°[Þ Ã¹¿n 6)×Q×'Î}îZ—«\ðŽ¶·ÝíWtkDÞírÓºG(äp1Ó]ï G½T:¯t1cß~õ+¾æ=ï~Ë+?ö¶WXï,€)tàúú÷@ùoø+¥§·¸‰@j Œà7ºC ìPÇ8a CwÁ!>n… \¨øÊ÷Y*^˜}ï{šW¬b-¶×‹a\°ŸÅøÑ11|¼a#—Äù+±‰›óXÕ>²+2K%¯Ø]N¦¬ŒÃpã9¶#ÆË’Õ2Ý*o•Ç)3•Í\ ,cùÊ n2†át¼ªKÊ«cv/ŒæAåY·l®‚šÛþf #ÙËÕ0+ßLR“ÐÂÄÝóCa ©Ï` 4}…1%·é¿‚†¡¢iÈèFwÚ¶±¤ý|jáI Ñp&²¥EœèOgòÎú5‹YMÔT+XÈöâ4¬[Ík7ÿšJ²¦AÚpMj[J×øuu¥_ÍeSÚ›•%™„ìd;×ÎÞµxMíÄžöÛ[nL1zmQG{=Ê^ö´'ýnU¯úÈÒ®-iéÍA(kvÛ¬ãwŒ“ûY€ƒ[ØâN³½ï]í|Ózß Ï0c|ð€ƒ6²·mx¤IcY‹/Ußs}¸q=>dŒ¯-â'x¬,rÝ€\‘ ‰ÆnˆVæ)§8ÂßÒÖþ/{ˆæ.dzu×Àô¼p•‰¢‡ÏjÛ)ž\7vJËÂpîó–bé×ôªSœî@¬£µÌ°ñ`¨žj$ )<ÝÚi*4”ÌãhGí Å*PuÚ;aÙÇ¡!µÜ×óó’êÜú´ÉGu©ª»~îO©*Ù]3á:"?RÇ{ãqx–ÿý “×NkZLÌ!þ|@ÊûGSX™ ‘œ?Ëã?ߟÐÇ=ˆg½h"zרއ®—´&sùØ¿höÞ»="õW Áëôp¾ OÆ÷á+?{kV¸üèÏã«CËšA¥}Ÿ\´žV̾÷Á{#†Sü„ü¾ùÍþ»¿ûço?ŒŒ·~þ–ßýô/üçO¾úë¿®îº~+÷€¼05À”Dh€¬ãHÜwøw€ ØO5ãOùç€h#H€ã“|(}é·D‚%—0èQ!h‚É42 (-$x‚-¨y椂+x.HƒñBy¾§A Xƒ;ø?k‘Q9¨ƒ<肳J€Bˆ„/¨Pû´^3˜„ H„L¨N?ø„Uˆ&ÂCD…VÈ…ªƒž†ƒ\(†„ú”…bH¡G9æäQ‡†08UnØN…ÔSø†XF›æ@_·syh‚„XÚ2ˆ€‚w¢snGG††èqrt–3çˆ8%‘((´E‰•Xþ—Hr·‰œè~+‚‰‚^Ÿ(Šíg ¥Èd (p©¨ŠÖmÞ†Š°è}«ÈlAöжx‹½Di´¸‹¼ˆ}Œ÷‹Í6‹Â}Ę‹ÜvŒÈ¨|ÊØŒ(oθ|ÐøñgÔ¸¾¸ŒÒHnÚXÜxØØàxFÖøÆ8æˆzèŒÿ6Žì¨2îX‹Ì¸ŽòˆD¸xðøŽø˜²¸öXþØ3¤˜Žð69NŠH'q¡¨É ©ŽE‘ɹfy‘º‡ˆ9‰lÕ‘9Iƒè@&9’$’Ù¡l—’itVUy€‡3ù’S°ÇRxx“¸×“?©K@)”4”EMY‡F‰”@””KÙvLé”ö”Q)oRI•7S•Wy…X©•=¸•WÙˆ]Ù…< –p(–cé€_i–I(9ÅÆ–mé–o —q)—sI—u P;pxp-1.2.9/doc/manual/html/pic/node_general.gif0000644000175000017500000000344113055274552017642 0ustar gerdgerdGIF87aˆ€¡ÿÿÿ¿¿¿,ˆ€þŒ©Ëí£œ´Ú‹³Þ¼û/âH–扦êʶî ÇòL×öçúþ‚þ ‡Ä¢ñø!—̦ó JÊ©õŠÍj·Á*÷ ‹ÇN/ùŒN«× 3û Ë™î¹ýŽÏOêú¾ÿÇ8HX¨%h˜¨¸X„Èøyá(Yiyi@‰¹Éi¨Ù Š÷)Zº`:EšÊJE" PÒº´:[*›«›[k ú+ÙkÛ °‹¼+ìólµL]<‹›l K!½à¬ •==|=Λ!¼¼Ý6â ëê\ÕÐNò`ÒoŸ.zLN¾ÏDׯU‚s39d6XA~›üý7_Dþ‚×il(OÚ½3Î“Ç #8ŠŠ,^Ĉ¡[Cg2|È1áC“dâãÉ’Ë—×€ætWó ÇL²ê\ï—Ó QÙ Ú’èÅ«8+øäFh%ÖACµ&»ºˆØ1kÇö)kö¬[_\çþW™Ýžu÷êÁ›·œ_m}ßËb½4}}ÔÖp €±´fÚìe›Íu–üfqeË ’>ûöôšÅÇDë2zóhÊ´êÒN…'õ¶Ó©³y/”ªOµPŒŠ]Çò:3³fÉqº‰}3µA‰Â!†‰ÚD”:wÞ®í1zîÝ­V·~WŸ&/´ ÿ}wà·K?OÆøËºèþ|'TjÆ=¾é†ÙI‘Uõ~-é·ULÖDÖ} ~!Uz¯MY‚€d8!èXˆ„ÔˆØáÚO‰'©ø7éC¢)²øŒOeØ;$yÌŽBÅHcý=e}ô9èã§=1cß($’h‚t™iÞ0Ye’¤†ìh°R€íôSY´íTà—™ÙçJß…§œ”ŒÄÍ‘³Q¥å$\–AÝ–y2‡P+*÷yï¥(h’V~¤Œò‘$^}}šó'rBt™’6¨šh2לNî-Wx’©GÚi•š§¡OµùwgT»ÅI««¯Æ¦e§Ûtê\©B™þè žV:]©Jz ]¨Ã’)ip¤~yìQvžJ-¤Ý[š¶²eÚ(¨Ó†:îq*ݪ¬¿úÚl™ýÕ3 ®ÂËWšu2*/€ÑîÈí§çÆk«·¾‘všŠ´0¹îƒp»ÍŒëpvíú!Ȩû/±ó ò¹ÌZ/¡ +ìì¨ ÛÆš¢ë—˜FÁ‚™ú;¯øškÎÃx0’,ÛÆð¬ïˆÌ”mü1Ó(ƒ¶–Æ—}±»[}õÓ=u+±pMþ€BG¯;ëËeOÚ\w õÌN6ñHyõ\_¿ vÜr×ͯÛù·ž|‡ 7¿Lóswàp#p˜…x"‰+þŽçà„[^qäžhNùÅi½7ÌAMÞ¹/oùÒœo¸zé§:êX‡CºëfÏ.;îªïU»í˺î»Ûݺë±ozz²ÅçÑ»ïÆÚQê¿/õ7.ºãÒOïVóΧ­TÈo/£õo¿i­•g?â÷2û£úë ßù*Ò¤üڳϊ÷¥§*3q&yås_vÓˆ)%A€ˆ³ß„èqr†´s ‚ ½’Ï`,†ÿ§´®Ì3!œÆ—à-°I¼‰’³pB'• DA›`5hø™Î‡ ˆ!‹nXÑ Ð?|H¡fˆaiÒÇ¢ ñJä]þ^rÈ ¥/‹Ø˜ZívÍpñBT £%¦X1’1&(“…¾h4ªFŒ™DÙxÇÐŽ Â^OúèÇ=ŽD£dè¨_²‹^Y$!/õHÄ-2À˜$l, C.q’”´'‚H¹ümŒ `@yÅS–Ò,Ld$#4é.¶R0Ú`¥bˆ(HSbC”¯Œ¤ ¯ˆZæ—!x/K+…¯ f%—¹KeS˜Dd¦4¹ R沚Ñì&6ÙkŠó›) §7ǹÆlj“šÕ bxšѠ³ŽÏ\&^àâKfäÓñt§3=N—°f›íä&=Õ¹N€š“#˜f=þ¡‰Ã{Ô %g!’i)±r¢gÙ(G¯)E=&T¡g™¥CÙ© “ž”¤)Íâ>8҇汘ŽldMES|Üt•}DËN{™S–šQ‘=åãLT•§C%ê‡ñR¾1ƒNmªQsT ŒnÒªW5e¹:ʤ u+ŸÃjú®èE±Jä‰,RiÜšVµÊ”ˆBÜOøT‘¨²¤¡ê!Ý+Zš¿VÖ0¬r¡8X°ÑÉz-¬ó´êؤB6²9,eGjÙË®3³š%%g;kÀÏ‚ö{¢­ïJkZã56µ2\-ki„Úׂе²-Qlk{>ñ`·¼í­o Üà w¸Ä½A ;pxp-1.2.9/doc/manual/html/pic/node_term.gif0000644000175000017500000000742513055274552017202 0ustar gerdgerdGIF87aÇ-¡ÿÿÿ¿¿¿,Ç-þ Ž©Ëí£œ´Ú‹³Þ¼û†âe扦êʶî ÇòL×öçúÎ÷þ Ú¢ñˆL*—̦óù#B§ÔªõŠÍj™Ò­÷ ‹ÇäY·ŒN«×ì6íìŽËçô:`Ïë÷ü¾ î(8HˆXˆ˜¨¸¨sÈøÉè(YiyYG‰¹ÉÙ ¦é*:ºJzŠšŠcªÚêúz ë³0k;'{{ƒ Ðë‹ Œ–+sà‹œL\̬´Ü¬"L­Œ=õœm0]ýýË-^z=n Žn¾´ íž^ÎNß8_Ÿ~ïoÜÏŸ¾}àþ;¸Â³¿;Ý­XR\Ð_Çâ%åù”'½Ÿ>ùMSЫeÔ1[Õtµùu¡Ã¦L³’EV&-i…ÍFÕC^LéÖEKgë5ŠIÛ‰‹ °ª¹úšž•vÖ;k•À³·[¬ÉÏt©³˜àÁ$yö–€¤Æ“K˜–lZJd¶¬S¯Þ«8aæn³CmN¥õjhiG¿i].xëÔ¥W‡ò–mrK·Q-½[›Œ™ÇO'"Üuåèn—känS(ÆÓ^ž=8äóäóïÎü=Pñ/‡§éË>{õëÀþ)ëãLòÍGßP( xD_1aÇmªQÇàv°•Ñ\âV`?§ԆzØÊaбbë™SâBÄN”¬¸‹}J%£(ó<Ç”Œù|¢ãŒÒôÇRpð•¢¥Mõ#Bae–#ŒùÂR#'Qx Ux”›x‰˜%—‡I­ržjg ® ŠKcäj)í²ñš©”ý½ŠnÞªWݪ{ˆªÈ¹ç²šnƒŠ. *qðòelƒþzツ(¬p¬ÿóà ¬v¹à¶jRKf_\RÃQxL”Š Wkåk5r)§|l%šx+7,·LÅÌV¼ mÌpqõ!>6ç€ïÂø³E¯rôIÛì+Km’ÒBêÓIÓÆÒ¼µðÕdxý+Ž…Øµf¸d²õ—`×@u&n'œö"mÛ¹¶ZFSÉ"s;S·}:ÉØy5­ÇÞYGu÷Þì,3keGälþŸãƒ<>çyË…ù³x{¤‹áX— ºãÏ9Ié@^ $¬«~(n’¼;¢Ëw×¹×~É톚ï@Ø…–ð¼›K;´B&¯Ü>Ư+óHCG;Ž9A?»ôCźõxaŸ}ïôuî}}àÇ\ÆQ¾hçî²úëg-¿öï“hÿ9õ%ÿü÷>ªþùï>Ìßÿba@V p€_[`ø<;9Pl dà@yxÏkí“Ç/÷À„8eƒ^iñzóA«eÐ*'Dá04ˆºˆ$„ï‹`‚ÆÒ$Ïð£„cMYZhÁn…w1‹Ä/XÄ."*bV„Ø8o Ÿ™¢þù(„‘Âä¦0PDETE'>‘€Y¬âgCÃóÙÐTdbðb¸DD72taU–ÆáŽ>,ˆÒ*˜Gì­‘üc!ïˆÇÙ’Œý ¤ Ù¢FòO’ˆ,$#©¾ºup<•´dú24šýu2‘ñ_^@9JR–ÒEäÏ%Ù»&ÊC4âK^ K—™€7& Ûh¬7ÈTZkTî¡ÉЦAaF1W²žâމ6gS™Š"¦–r‘<ÆQÓ(Žô.·)¶@â œœ&ÌEÎÿ™s¤Jg C¸¥oº³g0©Ù5ºÀ”&ý—Böw¦ôwn2,—tÊGRþ€‚2ZÇ6ˆã“Ç1Å’SèÁ{­Ò.ˆ÷ Xwž‡›’z]ô ð—hÞtNÇñ¤‘{1(xÃr|…'/Ý (o@è^GW/F…,axê8A(ƒ—vvõ‚=èJá§<84D€âx¾×)ag…&XX(yÒ7Nè"P¸€E˜yoñ§- R0mØ€WI)(†cx€ì”Ó².aS„®GRþ¢{|èØ„hQdH…h;Q1#Xq¯—àX¢8ê1|]h|KÈ„ÛCˆ\þC÷G_òç3'ˆš˜eœXaD&cá_ªèF*Ö‰åÅE‰8Çg/î7ˆê%M'Ôc¶=¶‹gvã4pÈ–JrCfFEFWvIVdFÖ:HuÅx‹Þba¤eòåcjÖŠ ð\t# 'LÆ8GkÖbÈx̸cOöuá(Š™†C–Ž-ÆóXMFGŒ åŽñ2ŽÕˆK†–ñµb½ÈfЈš:ÖžˆWŸ}¶±MäH~ÀxK_³j‹ñ{)k±¶aDSyIŠsøcRáîd‘&iXÁ750.óD€,Ù’Jó3Ø4‘y'“¨B“5™5wå…½Òsõ~=þ)X;׎A)|@QEi”üõK‚1tÞ¦ 鉺“9¹hYé}]™/`qysû6–d%–e¹RhiUg©–/Õmi4o —C4—IÅ–ur‰—Ü´—@u—} €‰S)˜>¡—…‰’ˆR„©˜¸q˜)’™QŒ)™£@™•i‰™Û·|üçÄ`8Jév9ˆUKii݆‡QPoc7p²&Dø…í䚺Ò2ZItp8ƒ;8s¸£F,—7­÷)ÂÁ{Y›‡×+¿I‰Þ!œÄ)‚wg)ôÂ…mBœgò)ÏYÃU¹²ñ'r§“s·7’ƒ*Å9P¶¹GÇyÛi†þB9ƒ5¸)aˆñÙ#YÒžz÷ž3x88+¨‘Ÿ")úy-ñùŸ‚1ØŸ:ò›  Õyƒ°ižG†ƒŠ„6÷188ô xJØz%Ç%­²ž%(€w‡º,oØ#€ Ÿ j,¿¡2ˆx +¯–„•¢*…ØLÆIž›W-Ò9…^·yTØ£Èw¤q¤ۂ1´hÀÓL{XsîBžœW…Nš‡¨-:¥Ù2æ z (V r„r'¦qâG1$Mºž–q‚ MgÚ˜!¥2¢p§€c*žÓÁˆ`úyŠ-(ê!¨|[*%|¥pÚ¨Dª¨øY ˜¢*h*©}üyczLoê¨têiTˆs´H¨Ââu|ø*Ë颬÷-Âù£#J©Ýyw§yª“—JØy¹§!rz©{b«è£xç.ž¬·*ÿÁªÆ: ß«±Z¢°º¦øš½9t¨²·ˆ—.ãÈG$\:¢‹ˆœUÊ•(+ÙY«ÚЍø¬S®À颖Á®ŸYœË©,íJ¥BÊ1÷éyµÑ­¨€X8sÚϧ’Õ#°†©¯‘©™õQ TBu™±°›] Pk±±”±û„±>[° ²"KNK²r3±'ûl*«L&˲Iò²Åè¤]I³5k³7‹³9«³;˳j;pxp-1.2.9/doc/manual/src/0000755000175000017500000000000013055274552013577 5ustar gerdgerdpxp-1.2.9/doc/manual/src/pic/0000755000175000017500000000000013055274552014352 5ustar gerdgerdpxp-1.2.9/doc/manual/src/pic/extension_general.fig0000644000175000017500000000321513055274552020553 0ustar gerdgerd#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 1575 2250 229 229 1575 2250 1800 2295 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 1575 3375 225 225 1575 3375 1800 3375 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 675 3375 229 229 675 3375 900 3420 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 2475 3375 229 229 2475 3375 2700 3420 1 3 0 1 0 7 100 0 10 0.000 1 0.0000 3600 2475 180 180 3600 2475 3780 2475 1 3 0 1 0 7 100 0 10 0.000 1 0.0000 2880 2475 180 180 2880 2475 3060 2475 1 3 0 1 0 7 100 0 10 0.000 1 0.0000 4320 2475 186 186 4320 2475 4500 2520 1 3 0 1 0 7 100 0 10 0.000 1 0.0000 3600 1485 186 186 3600 1485 3780 1530 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 675 3150 1395 2385 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 1575 2475 1575 3150 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 1755 2385 2475 3150 2 1 1 1 0 7 100 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 1537 2010 3412 1462 2 1 1 1 0 7 100 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 3412 1537 1672 2047 2 1 1 1 0 7 100 0 -1 4.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 810 3195 2707 2512 2 1 1 1 0 7 100 0 -1 4.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 1740 3217 3442 2580 2 1 1 1 0 7 100 0 -1 4.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 2640 3210 4177 2610 4 0 0 80 0 14 12 0.0000 4 75 105 3555 1530 x\001 4 0 0 80 0 14 12 0.0000 4 75 105 1530 2295 n\001 4 0 0 80 0 12 12 0.2967 4 135 1365 1658 1950 n # extension\001 4 0 0 80 0 12 12 0.2967 4 135 840 2475 1950 x # node\001 4 0 0 80 0 16 12 0.0000 4 135 1140 1020 4050 The node tree\001 4 0 0 80 0 16 12 0.0000 4 135 1245 3225 3285 The extensions\001 pxp-1.2.9/doc/manual/src/pic/node_add.fig0000644000175000017500000000727713055274552016613 0ustar gerdgerd#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 6141 1350 242 229 6141 1350 6379 1395 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 6141 2250 242 229 6141 2250 6379 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 5426 2250 242 229 5426 2250 5665 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 6856 2250 242 229 6856 2250 7094 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 7571 2925 242 229 7571 2925 7809 2970 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 8524 2925 242 229 8524 2925 8762 2970 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 8047 2250 242 229 8047 2250 8285 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 1866 1350 242 229 1866 1350 2104 1395 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 1866 2250 242 229 1866 2250 2104 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 1151 2250 242 229 1151 2250 1390 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 2581 2250 242 229 2581 2250 2819 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 3296 2925 242 229 3296 2925 3534 2970 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 4249 2925 242 229 4249 2925 4487 2970 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 3772 2250 242 229 3772 2250 4010 2295 1 1 0 1 0 7 100 0 15 0.000 1 0.0000 8325 1350 242 229 8325 1350 8563 1395 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.76 123.53 5910 1440 5402 2017 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.76 123.53 6109 1590 6101 2025 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.76 123.53 6307 1537 6697 2070 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.76 123.53 7832 2347 7602 2692 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.76 123.53 8150 2452 8349 2752 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.76 123.53 5490 2017 5958 1492 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.76 123.53 6164 2010 6173 1575 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.76 123.53 6768 2025 6355 1470 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.76 123.53 7673 2715 7880 2415 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.76 123.53 8412 2707 8222 2415 2 1 1 1 0 7 95 0 15 4.000 0 0 -1 0 0 2 6387 1372 8023 2017 2 2 0 1 0 7 95 0 -1 0.000 0 0 -1 0 0 5 4950 900 9000 900 9000 3375 4950 3375 4950 900 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.75 123.51 1635 1440 1127 2017 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.75 123.51 1834 1590 1826 2025 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.75 123.51 2032 1537 2422 2070 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.75 123.51 3557 2347 3327 2692 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 61.75 123.51 3875 2452 4074 2752 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.75 123.51 1215 2017 1683 1492 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.75 123.51 1889 2010 1898 1575 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.75 123.51 2493 2025 2080 1470 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.75 123.51 3398 2715 3605 2415 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 61.75 123.51 4137 2707 3947 2415 2 1 1 1 0 7 95 0 15 4.000 0 0 -1 0 0 2 2112 1372 3748 2017 2 2 0 1 0 7 95 0 -1 0.000 0 0 -1 0 0 5 675 900 4725 900 4725 3375 675 3375 675 900 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 8197 1545 8055 2010 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 8137 2025 8280 1590 2 1 0 3 0 7 95 0 -1 0.000 0 0 -1 1 0 4 2 1 2.00 120.00 180.00 7875 1500 7620 1965 7845 1920 7485 2355 4 0 0 95 0 14 13 0.0000 4 90 120 6094 1379 x\001 4 0 0 95 0 14 13 0.0000 4 120 120 7991 2265 y\001 4 0 0 95 0 14 13 0.0000 4 90 120 1819 1379 x\001 4 0 0 95 0 14 13 0.0000 4 120 120 3716 2265 y\001 4 0 0 95 0 12 12 0.0000 4 150 1785 6300 1125 x # append_node y\001 4 0 0 95 0 12 12 0.0000 4 150 1785 2160 1170 x # append_node y\001 pxp-1.2.9/doc/manual/src/pic/node_clone.fig0000644000175000017500000000737513055274552017162 0ustar gerdgerd#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 2700 1800 229 229 2700 1800 2925 1845 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 2025 2700 229 229 2025 2700 2250 2745 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 3375 2700 229 229 3375 2700 3600 2745 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 6345 1800 229 229 6345 1800 6570 1845 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 5670 2700 229 229 5670 2700 5895 2745 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 7020 2700 229 229 7020 2700 7245 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 8325 1800 229 229 8325 1800 8550 1845 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 7875 2700 229 229 7875 2700 8100 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 8775 2700 229 229 8775 2700 9000 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 6345 2700 229 229 6345 2700 6570 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 5895 3600 229 229 5895 3600 6120 3645 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 6795 3600 229 229 6795 3600 7020 3645 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 2700 2700 229 229 2700 2700 2925 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 2250 3600 229 229 2250 3600 2475 3645 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 3150 3600 229 229 3150 3600 3375 3645 2 1 0 5 0 7 95 0 -1 12.000 1 0 -1 0 0 2 4050 2610 4725 2610 2 1 0 5 0 7 95 0 -1 12.000 1 0 -1 0 0 2 4050 2745 4725 2745 2 1 0 5 0 7 95 0 -1 12.000 1 1 -1 0 0 3 4500 2385 4950 2655 4500 2970 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2490 1905 2025 2467 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2827 2002 3202 2542 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 2115 2475 2535 1965 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 3255 2505 2872 1957 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6135 1905 5670 2467 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6472 2002 6847 2542 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 5760 2475 6180 1965 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 6900 2505 6517 1957 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 8160 1957 7860 2460 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 8407 2032 8625 2520 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 7942 2467 8212 2010 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 8685 2475 8467 1987 2 2 0 1 0 7 80 0 -1 4.000 0 0 -1 0 0 5 1575 1350 9225 1350 9225 4050 1575 4050 1575 1350 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 6382 2460 6382 2032 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6307 2032 6307 2467 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6180 2857 5880 3360 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6427 2932 6645 3420 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 5962 3367 6232 2910 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 6705 3375 6487 2887 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 2737 2460 2737 2032 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2662 2032 2662 2467 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2535 2857 2235 3360 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2782 2932 3000 3420 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 2317 3367 2587 2910 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 3060 3375 2842 2887 4 0 0 80 0 14 12 0.0000 4 105 105 2655 1845 y\001 4 0 0 80 0 14 12 0.0000 4 105 105 6300 1845 y\001 4 0 0 80 0 14 12 0.0000 4 75 105 6285 2752 x\001 4 0 0 80 0 14 12 0.0000 4 75 105 2640 2752 x\001 4 0 0 80 0 12 12 0.0000 4 105 840 3690 2025 let x' =\001 4 0 0 80 0 12 12 0.0000 4 150 1890 3690 2205 x # orphaned_clone\001 4 0 0 80 0 14 12 0.0000 4 105 210 8235 1845 x'\001 pxp-1.2.9/doc/manual/src/pic/node_delete.fig0000644000175000017500000000614413055274552017315 0ustar gerdgerd#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 6 2550 2092 2865 2407 2 1 0 4 0 7 80 0 -1 0.000 1 1 -1 0 0 2 2595 2362 2820 2137 2 1 0 4 0 7 80 0 -1 0.000 1 1 -1 0 0 2 2595 2137 2820 2362 -6 6 1980 2430 3420 3870 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 2700 2700 229 229 2700 2700 2925 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 2250 3600 229 229 2250 3600 2475 3645 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 3150 3600 229 229 3150 3600 3375 3645 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2535 2857 2235 3360 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2782 2932 3000 3420 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 2317 3367 2587 2910 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 3060 3375 2842 2887 -6 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 2700 1800 229 229 2700 1800 2925 1845 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 2025 2700 229 229 2025 2700 2250 2745 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 3375 2700 229 229 3375 2700 3600 2745 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 6345 1800 229 229 6345 1800 6570 1845 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 5670 2700 229 229 5670 2700 5895 2745 1 3 0 1 0 7 95 0 15 4.000 1 0.0000 7020 2700 229 229 7020 2700 7245 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 8325 1800 229 229 8325 1800 8550 1845 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 7875 2700 229 229 7875 2700 8100 2745 1 3 0 1 0 7 95 0 10 4.000 1 0.0000 8775 2700 229 229 8775 2700 9000 2745 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 2737 2460 2737 2032 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2662 2032 2662 2467 2 1 0 5 0 7 95 0 -1 12.000 1 0 -1 0 0 2 4050 2610 4725 2610 2 1 0 5 0 7 95 0 -1 12.000 1 0 -1 0 0 2 4050 2745 4725 2745 2 1 0 5 0 7 95 0 -1 12.000 1 1 -1 0 0 3 4500 2385 4950 2655 4500 2970 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2490 1905 2025 2467 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2827 2002 3202 2542 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 2115 2475 2535 1965 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 3255 2505 2872 1957 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6135 1905 5670 2467 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6472 2002 6847 2542 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 5760 2475 6180 1965 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 6900 2505 6517 1957 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 8160 1957 7860 2460 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 8407 2032 8625 2520 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 7942 2467 8212 2010 2 1 0 1 0 7 95 0 -1 4.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 8685 2475 8467 1987 2 2 0 1 0 7 80 0 -1 4.000 0 0 -1 0 0 5 1575 1350 9225 1350 9225 4050 1575 4050 1575 1350 4 0 0 80 0 14 12 0.0000 4 75 105 2640 2752 x\001 4 0 0 95 0 12 12 0.0000 4 135 1260 3960 2250 x # remove()\001 4 0 0 80 0 14 12 0.0000 4 75 105 8280 1845 x\001 4 0 0 80 0 14 12 0.0000 4 105 105 2655 1845 y\001 4 0 0 80 0 14 12 0.0000 4 105 105 6300 1845 y\001 pxp-1.2.9/doc/manual/src/pic/node_general.fig0000644000175000017500000000266113055274552017470 0ustar gerdgerd#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 6 2925 900 4725 2295 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 3825 2025 229 229 3825 2025 4050 2070 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 4500 2025 225 225 4500 2025 4725 2025 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 3825 1125 225 225 3825 1125 4050 1125 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 3150 2025 225 225 3150 2025 3375 2025 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 3180 1800 3645 1275 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 3615 1207 3082 1815 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 3855 1792 3855 1350 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 3780 1350 3780 1807 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 3990 1297 4350 1867 2 1 0 1 0 7 100 0 15 0.000 0 0 -1 1 0 2 1 0 1.00 60.00 120.00 4402 1807 4020 1237 4 0 0 90 0 12 12 0.0000 4 75 105 3735 1170 x\001 4 0 0 90 0 12 12 0.0000 4 135 210 3060 2070 y1\001 4 0 0 90 0 12 12 0.0000 4 135 210 3735 2070 y2\001 4 0 0 90 0 12 12 0.0000 4 135 210 4410 2070 y3\001 -6 2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5 450 675 6030 675 6030 2475 450 2475 450 675 4 0 0 100 0 12 12 0.0000 4 150 2730 540 1440 x # sub_nodes = [y1;y2;y3]\001 4 0 0 100 0 12 12 0.0000 4 150 1575 4275 1035 y1 # parent = x\001 4 0 0 100 0 12 12 0.0000 4 150 1575 4275 1215 y2 # parent = x\001 4 0 0 100 0 12 12 0.0000 4 150 1575 4275 1395 y3 # parent = x\001 pxp-1.2.9/doc/manual/src/pic/node_term.fig0000644000175000017500000000515413055274552017022 0ustar gerdgerd#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 6 1665 2700 2835 3150 2 4 0 1 0 7 100 0 15 0.000 0 0 7 0 0 5 2835 3150 2835 2700 1665 2700 1665 3150 2835 3150 4 0 0 80 0 18 12 0.0000 4 135 930 1815 3015 "Cherries"\001 -6 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 2250 1125 225 225 2250 1125 2475 1125 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 1575 2025 225 225 1575 2025 1800 2025 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 2925 2025 225 225 2925 2025 3150 2025 1 3 0 1 0 7 100 0 15 0.000 1 0.0000 900 2925 242 242 900 2925 1125 3015 2 4 0 1 0 7 100 0 15 0.000 0 0 7 0 0 5 1485 4275 1485 3825 315 3825 315 4275 1485 4275 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 2085 1275 1582 1807 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 2407 1297 2940 1800 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 1417 2190 900 2692 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 1740 2190 2257 2700 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2 892 3180 892 3825 2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5 45 675 6525 675 6525 4950 45 4950 45 675 3 3 0 1 0 7 100 0 -1 0.000 0 0 0 22 2115 3645 2250 3600 2520 3555 2745 3510 2925 3555 3150 3690 3375 3735 3600 3735 3825 3735 4140 3825 4140 4005 4005 4185 3735 4230 3420 4185 3150 4230 2835 4275 2520 4230 2340 4140 2115 4095 1980 4005 1980 3825 2025 3735 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 3 3 0 1 0 7 100 0 -1 0.000 0 0 0 17 3465 1170 3645 1080 4050 1035 4320 1035 4545 1080 4770 1170 5130 1215 5355 1350 5400 1530 5265 1665 4860 1710 4455 1710 4095 1665 3780 1620 3555 1575 3420 1485 3420 1305 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 3 2 0 1 0 7 100 0 -1 0.000 0 0 0 5 2475 1215 2655 1350 2970 1440 3240 1395 3420 1260 0.000 -1.000 -1.000 -1.000 0.000 3 2 0 1 0 7 100 0 -1 0.000 0 0 0 5 1125 3060 1215 3397 1410 3607 1687 3727 2025 3720 0.000 -1.000 -1.000 -1.000 0.000 4 0 0 80 0 18 12 0.0000 4 180 1065 375 4125 "An orange"\001 4 0 0 80 0 18 12 0.0000 4 90 315 750 2985 \001 4 0 0 80 0 18 12 0.0000 4 135 315 1410 2085 \001 4 0 0 80 0 18 12 0.0000 4 90 315 2790 2070 \001 4 0 0 80 0 18 12 0.0000 4 90 315 2100 1200 \001 4 0 0 100 0 16 12 0.0000 4 135 795 3600 1260 attributes:\001 4 0 0 100 0 16 12 0.0000 4 180 1680 3600 1485 "att" -> Value "apple"\001 4 0 0 100 0 16 12 0.0000 4 135 795 2250 3780 attributes:\001 4 0 0 100 0 17 12 0.0000 4 180 5910 390 4725 An orangeCherries\001 4 0 0 100 0 16 12 0.0000 4 180 1800 2250 4005 "att" -> Value "orange"\001 pxp-1.2.9/examples/0000755000175000017500000000000013055274552012604 5ustar gerdgerdpxp-1.2.9/examples/Makefile0000644000175000017500000000115313055274552014244 0ustar gerdgerd.PHONY: all all: .PHONY: clean clean: .PHONY: CLEAN CLEAN: clean $(MAKE) -C xmlforms CLEAN $(MAKE) -C validate CLEAN $(MAKE) -C readme CLEAN $(MAKE) -C simple_transformation CLEAN $(MAKE) -C namespaces CLEAN $(MAKE) -C eventparser CLEAN $(MAKE) -C pullparser CLEAN $(MAKE) -C xhtml2html CLEAN .PHONY: distclean distclean: clean rm -f *~ $(MAKE) -C xmlforms distclean $(MAKE) -C validate distclean $(MAKE) -C readme distclean $(MAKE) -C simple_transformation distclean $(MAKE) -C namespaces distclean $(MAKE) -C eventparser distclean $(MAKE) -C pullparser distclean $(MAKE) -C xhtml2html distclean pxp-1.2.9/examples/namespaces/0000755000175000017500000000000013055274552014723 5ustar gerdgerdpxp-1.2.9/examples/namespaces/Makefile0000644000175000017500000000144613055274552016370 0ustar gerdgerd# make preprocess: make bytecode executable # make preprocess.opt: make native executable # make clean: remove intermediate files # make CLEAN: remove intermediate files (recursively) # make distclean: remove any superflous files # make install #---------------------------------------------------------------------- BIN = /usr/local/bin preprocess: preprocess.ml ocamlfind ocamlc -g -o preprocess -package pxp,str -linkpkg preprocess.ml preprocess.opt: preprocess.ml ocamlfind ocamlopt -o preprocess.opt -package pxp,str -linkpkg preprocess.ml .PHONY: clean clean: rm -f *.cmi *.cmo *.cma *.cmx *.o *.a *.cmxa .PHONY: CLEAN CLEAN: clean .PHONY: distclean distclean: clean rm -f *~ depend depend.pkg rm -f preprocess preprocess.opt .PHONY: install install: cp preprocess $(BIN) pxp-1.2.9/examples/namespaces/README0000644000175000017500000000507213055274552015607 0ustar gerdgerdThis example demonstrates namespaces: it's a tiny macro preprocessor. You can put statements into your XML code, and later expand macros by statements. See macro.dtd for the DTD and sample.xml for an example in XHTML. Using the preprocessor: Do ./preprocess sample.xml which prints the converted text to stdout. Note that the preprocessor runs in a mode which is more than well-formedness mode and less than validating mode. The DTD contained in the preprocessed XML text is replaced by macro.dtd (except the general entities which are copied), and macro.dtd specifies that the known parts of the macro language are validated, and that all other elements and attributes are not validated. For example, the preprocessor does not check whether sample.xml is valid XHTML. The replacement of the DTD is performed by the ~transform_dtd parameter of parse_document_entity (see preprocess.ml). Notes to the namespaces: (1) The program uses two namespaces for its own purposes: "http://www.ocaml-programming.de/macro" is the identifier for the namespace containing the and statements. "http://www.ocaml-programming.de/macro/use" is the identifier for the namespace containing the defined macros. (2) In preprocess.ml you will find something like if node # node_type = T_element "macro:define" then ... This works even if the namespace "http://www.ocaml-programming.de/macro" is bound to a different prefix than "macro", because the parser rewrites the prefixes automatically. The DTD macro.dtd contains a processing instruction letting the parser replace all prefixes declared for the namespace identifier "http://www.ocaml-programming.de/macro" by "macro". The namespaces chapter of the manual explains the rationale behind that. (3) You find another test node # namespace_uri = macro_use_uri where macro_use_uri is "http://www.ocaml-programming.de/macro/use". This is just another way to check whether an element belongs to a certain namespace. Other comments: (1) The preprocessor outputs the file always in UTF-8 encoding. (2) If the input file has a DOCTYPE line, this line is reproduced in the output. However, the preprocessor does never output the internal subset of the DTD, if any. (3) Although the preprocessor does not validate the input fully, the specified DTD is completely read in. This is necessary to get all the general entities. pxp-1.2.9/examples/namespaces/macro.dtd0000644000175000017500000000316013055274552016521 0ustar gerdgerd pxp-1.2.9/examples/namespaces/preprocess.ml0000644000175000017500000001453613055274552017453 0ustar gerdgerd(* $Id$ *) open Pxp_document open Pxp_tree_parser open Pxp_types exception User_error of string let user_error (where,line,pos) subject = let message = (if line <> 0 then "In " ^ where ^ ", at line " ^ string_of_int line ^ " position " ^ string_of_int pos ^ ":\n" else "" ) ^ subject in raise(User_error message) ;; let macro_use_uri = "http://www.ocaml-programming.de/macro/use" ;; let collect_macro_define tree = let container = Hashtbl.create 10 in (* Collect all macro:define elements and put them into [container]. * Remove these elements from the tree. *) iter_tree ~pre:(fun node -> if node # node_type = T_element "macro:define" then begin let name = node # required_string_attribute "name" in if Hashtbl.mem container name then user_error (node # position) "Macro already defined"; if List.length (node # sub_nodes) <> 1 then user_error (node # position) "Macro must contain exactly one subnode"; node # remove(); Hashtbl.add container name (node # nth_node 0); raise Skip (* Do not iterate over the children of [node] *) end ) tree; container ;; let parameter_re = Str.regexp "\\$[-a-zA-Z0-9_.]+";; let replace_macro_use container tree = let replace_params position data atts = let splitted = Str.full_split parameter_re data in let splitted' = List.map (function Str.Text s -> s | Str.Delim s -> let param_name = String.sub s 1 (String.length s - 1) in ( try let param_value = List.assoc param_name atts in (* or Not_found *) match param_value with Value v -> v | _ -> assert false with Not_found -> user_error position ("Parameter " ^ param_name ^ " not found") ) ) splitted in String.concat "" splitted' in let replace_use position name atts = try let subst = Hashtbl.find container name in (* or Not_found *) (* Make a copy of [subst], and replace the parameters: *) map_tree ~pre:(fun node -> node # orphaned_flat_clone) ~post:(fun node -> match node # node_type with T_data -> (* It is possible that the data node contains * parameters *) let data = node # data in let data' = replace_params (node # position) data atts in node # set_data data'; node | _ -> node ) subst with Not_found -> user_error position ("Macro not found: " ^ name) in (* Make a copy of [tree], and replace the macro calls: *) map_tree ~pre:(fun node -> node # orphaned_flat_clone) ~post:(fun node -> match node # node_type with T_element "macro:use" -> let name = node # required_string_attribute "name" in let atts = node # attributes in let atts' = List.remove_assoc "name" atts in replace_use (node # position) name atts' | T_element _ when node # namespace_uri = macro_use_uri -> let name = node # localname in replace_use (node # position) name (node # attributes) | _ -> node ) tree ;; let read_macro_dtd config = Pxp_dtd_parser.parse_dtd_entity config (from_file "macro.dtd") ;; let copy_general_entities dtd1 dtd2 = (* Copy the general entities from dtd1 to dtd2 *) let names = dtd1 # gen_entity_names in List.iter (fun name -> let ent, is_external = dtd1 # gen_entity name in dtd2 # add_gen_entity ent is_external ) names ;; let transform config dtd filename = (* Read the document: *) let found_dtd_id = ref None in let found_root = ref None in let doc = parse_document_entity ~transform_dtd:(fun found_dtd -> (* Save the DTD ID: *) found_dtd_id := found_dtd # id; found_root := found_dtd # root; (* Copy general entities to [dtd]: *) copy_general_entities found_dtd dtd; (* Replace the found DTD by this one: *) dtd) config (from_file filename) default_namespace_spec in let root = doc # root in (* Collect the macro definitions: * (As a side effect, remove the definitions from the tree [root].) *) let definitions = collect_macro_define root in (* Expand the macro calls: *) let root' = replace_macro_use definitions root in (* Output the result: *) let root_element = find (fun node -> match node # node_type with T_element _ -> true | _ -> false ) root' in let default_prefix = root_element # normprefix in print_string "\n"; (* Output the DOCTYPE line, if needed. This is a bit delicate. *) ( match !found_dtd_id with Some (External _) | Some (Derived _) -> let id = (match !found_dtd_id with Some (External x) -> x | Some (Derived x) -> x | _ -> assert false ) in (* If the id is Derived, the internal subset of the DTD is * silently dropped. *) print_string " (* Remove the default prefix: *) let p, l = Pxp_aux.namespace_split r in print_string (if p = default_prefix then l else r); | _ -> assert false ); ( match id with System sysid -> print_string " SYSTEM \""; print_string sysid; print_string "\"" | Public(pubid,sysid) -> print_string " PUBLIC \""; print_string pubid; print_string "\" \""; print_string sysid; print_string "\""; | _ -> assert false ); print_string ">\n"; | Some Internal | None -> (* Internal DTDs are silently dropped *) () ); root' # write ~default:default_prefix (`Out_channel stdout) `Enc_utf8 ;; let main() = let filename = ref "" in Arg.parse [] (fun s -> if !filename <> "" then raise(Arg.Bad "Please, only one file at once!"); filename := s ) "usage: preprocess [ options ] filename"; if !filename = "" then user_error ("",0,0) "No input file"; let config = { default_namespace_config with encoding = `Enc_utf8; enable_pinstr_nodes = true; enable_super_root_node = true; enable_comment_nodes = true; } in let dtd = read_macro_dtd config in transform config dtd !filename ;; try main() with User_error message -> prerr_endline message; exit 1 | other -> prerr_endline (string_of_exn other); exit 1 ;; pxp-1.2.9/examples/namespaces/sample.xml0000644000175000017500000000114113055274552016723 0ustar gerdgerd $content Sample page

Sample page

A Caml program:

s = "Hello world"
print_endline s ;; pxp-1.2.9/examples/namespaces/sample2.xml0000644000175000017500000000130613055274552017010 0ustar gerdgerd $content Sample page Sample page A Caml program: s = "Hello world" print_endline s ;; pxp-1.2.9/examples/namespaces/xhtml-lat1.ent0000644000175000017500000002701513055274552017433 0ustar gerdgerd pxp-1.2.9/examples/namespaces/xhtml-special.ent0000644000175000017500000001006013055274552020202 0ustar gerdgerd pxp-1.2.9/examples/namespaces/xhtml-symbol.ent0000644000175000017500000003345713055274552020106 0ustar gerdgerd pxp-1.2.9/examples/namespaces/xhtml1-strict.dtd0000644000175000017500000006270613055274552020156 0ustar gerdgerd %HTMLlat1; %HTMLsymbol; %HTMLspecial; pxp-1.2.9/examples/readme/0000755000175000017500000000000013055274552014041 5ustar gerdgerdpxp-1.2.9/examples/readme/Makefile0000644000175000017500000000127613055274552015507 0ustar gerdgerd# make readme: make bytecode executable # make readme.opt: make native executable # make clean: remove intermediate files # make CLEAN: remove intermediate files (recursively) # make distclean: remove any superflous files # make install #---------------------------------------------------------------------- BIN = /usr/local/bin .PHONY: readme readme: $(MAKE) -f Makefile.code readme .PHONY: readme.opt readme.opt: $(MAKE) -f Makefile.code readme.opt .PHONY: clean clean: rm -f *.cmi *.cmo *.cma *.cmx *.o *.a *.cmxa .PHONY: CLEAN CLEAN: clean .PHONY: distclean distclean: clean rm -f *~ depend depend.pkg rm -f readme readme.opt .PHONY: install install: cp readme $(BIN) pxp-1.2.9/examples/readme/Makefile.code0000644000175000017500000000162213055274552016413 0ustar gerdgerd#---------------------------------------------------------------------- # specific rules for this package: OBJECTS = to_html.cmo to_text.cmo XOBJECTS = $(OBJECTS:.cmo=.cmx) NAME = readme REQUIRES = str pxp readme: $(OBJECTS) main.cmo ocamlfind ocamlc -o readme -custom -package "$(REQUIRES)" \ -linkpkg $(OBJECTS) main.cmo readme.opt: $(XARCHIVE) main.cmx ocamlfind ocamlopt -o readme.opt -package "$(REQUIRES)" \ -linkpkg $(XOBJECTS) main.cmx #---------------------------------------------------------------------- # general rules: OPTIONS = OCAMLC = ocamlfind ocamlc -g -package "$(REQUIRES)" OCAMLOPT = ocamlfind ocamlopt -package "$(REQUIRES)" OCAMLDEP = ocamldep OCAMLFIND = ocamlfind depend: *.ml *.mli $(OCAMLDEP) *.ml *.mli >depend .SUFFIXES: .cmo .cmi .cmx .ml .mli .ml.cmx: $(OCAMLOPT) -c $< .ml.cmo: $(OCAMLC) -c $< .mli.cmi: $(OCAMLC) -c $< *.mli: include depend pxp-1.2.9/examples/readme/main.ml0000644000175000017500000000333013055274552015316 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) open Pxp_types open Pxp_document open Pxp_tree_parser let rec print_error e = prerr_endline(string_of_exn e) ;; let run f a = try f a with e -> print_error e ;; let convert_to_html filename = (* read in style definition *) let document = parse_document_entity { default_config with encoding = `Enc_iso88591 } (from_file filename) To_html.tag_map in let root = document # root in let store = new To_html.store in root # extension # to_html store stdout ;; let convert_to_text filename = (* read in style definition *) let document = parse_document_entity default_config (from_file filename) To_text.tag_map in let root = document # root in let store = new To_text.store in let box = new To_text.box 79 79 in root # extension # to_box store box; box # output 0 0 stdout ;; let main() = let want_html = ref false in let want_text = ref false in let filename = ref None in Arg.parse [ "-html", Arg.Set want_html, " convert file to html"; "-text", Arg.Set want_text, " convert file to text"; ] (fun s -> match !filename with None -> filename := Some s | Some _ -> raise (Arg.Bad "Multiple arguments not allowed.")) "usage: readme [ -text | -html ] input.xml >output"; let fn = match !filename with None -> prerr_endline "readme: no input"; exit 1 | Some s -> s in match !want_html, !want_text with true, false -> run convert_to_html fn | false, true -> run convert_to_text fn | _ -> prerr_endline ("readme: Please select exactly one output format") ;; main();; pxp-1.2.9/examples/readme/readme.dtd0000644000175000017500000000116713055274552016000 0ustar gerdgerd pxp-1.2.9/examples/readme/to_html.ml0000644000175000017500000002231613055274552016045 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) (*$ readme.code.header *) open Pxp_types open Pxp_document open Pxp_dtd.Entity (*$-*) (*$ readme.code.footnote-printer *) class type footnote_printer = object method footnote_to_html : store_type -> out_channel -> unit end and store_type = object method alloc_footnote : footnote_printer -> int method print_footnotes : out_channel -> unit end ;; (*$-*) (*$ readme.code.store *) 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 <- number+1; footnotes <- footnotes @ [ number, n ]; number method print_footnotes ch = if footnotes <> [] then begin output_string ch "
\n"; output_string ch "
\n"; List.iter (fun (_,n) -> n # footnote_to_html (self : #store_type :> store_type) ch) footnotes; output_string ch "
\n"; end end ;; (*$-*) (*$ readme.code.escape-html *) let escape_html s = Str.global_substitute (Str.regexp "<\\|>\\|&\\|\"\\|@\\|:") (fun s -> match Str.matched_string s with "<" -> "<" | ">" -> ">" | "&" -> "&" | "\"" -> """ | "@" -> "@" | ":" -> ":" | _ -> assert false) s ;; (*$-*) (*$ readme.code.shared *) class virtual shared = object (self) (* --- default_ext --- *) val mutable node = (None : shared node option) method clone = {< >} method node = match node with None -> assert false | Some n -> n method set_node n = node <- Some n (* --- virtual --- *) method virtual to_html : store -> out_channel -> unit end ;; (*$-*) (*$ readme.code.only-data *) class only_data = object (self) inherit shared method to_html store ch = output_string ch (escape_html (self # node # data)) end ;; (*$-*) (*$ readme.code.no-markup *) class no_markup = object (self) inherit shared method to_html store ch = List.iter (fun n -> n # extension # to_html store ch) (self # node # sub_nodes) end ;; (*$-*) (*$ readme.code.readme *) class readme = object (self) inherit shared method to_html store ch = (* output header *) output_string ch ""; output_string ch "\n"; let title = match self # node # attribute "title" with Value s -> s | _ -> assert false in let html_header = try replacement_text (self # node # dtd # par_entity "readme:html:header") with WF_error _ -> "" in let html_trailer = try replacement_text (self # node # dtd # par_entity "readme:html:trailer") with WF_error _ -> "" in let html_bgcolor = try replacement_text (self # node # dtd # par_entity "readme:html:bgcolor") with WF_error _ -> "white" in let html_textcolor = try replacement_text (self # node # dtd # par_entity "readme:html:textcolor") with WF_error _ -> "" in let html_alinkcolor = try replacement_text (self # node # dtd # par_entity "readme:html:alinkcolor") with WF_error _ -> "" in let html_vlinkcolor = try replacement_text (self # node # dtd # par_entity "readme:html:vlinkcolor") with WF_error _ -> "" in let html_linkcolor = try replacement_text (self # node # dtd # par_entity "readme:html:linkcolor") with WF_error _ -> "" in let html_background = try replacement_text (self # node # dtd # par_entity "readme:html:background") with WF_error _ -> "" in output_string ch "
\n"; output_string ch (escape_html title); output_string ch "
\n"; output_string ch " if value <> "" 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 ">\n"; output_string ch html_header; output_string ch "

"; output_string ch (escape_html title); output_string ch "

\n"; (* process main content: *) List.iter (fun n -> 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 "\n"; end ;; (*$-*) (*$ readme.code.section *) 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 -> output_string ch ("<" ^ tag ^ ">\n"); title_node # extension # to_html store ch; output_string ch ("\n"); List.iter (fun n -> n # extension # to_html store ch) rest | _ -> assert false end ;; class sect1 = section "h1";; class sect2 = section "h3";; class sect3 = section "h4";; (*$-*) (*$ readme.code.map-tag *) class map_tag the_target_tag = object (self) inherit shared val target_tag = the_target_tag method to_html store ch = output_string ch ("<" ^ target_tag ^ ">\n"); List.iter (fun n -> n # extension # to_html store ch) (self # node # sub_nodes); output_string ch ("\n"); end ;; class p = map_tag "p";; class em = map_tag "b";; class ul = map_tag "ul";; class li = map_tag "li";; (*$-*) (*$ readme.code.br *) class br = object (self) inherit shared method to_html store ch = output_string ch "
\n"; List.iter (fun n -> n # extension # to_html store ch) (self # node # sub_nodes); end ;; (*$-*) (*$ readme.code.code *) 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 < l then match data.[i] with '\t' -> let n = 8 - (column mod 8) in String.make n ' ' ^ preprocess (i+1) (column + n) | '\n' -> "\n" ^ preprocess (i+1) 0 | c -> String.make 1 c ^ preprocess (i+1) (column + 1) else "" in output_string ch "

";
      output_string ch (escape_html (preprocess 0 0));
      output_string ch "

"; end ;; (*$-*) (*$ readme.code.a *) class a = object (self) inherit shared method to_html store ch = output_string ch " escape_html v | Valuelist _ -> assert false | Implied_value -> begin match self # node # attribute "readmeref" with Value v -> escape_html v ^ ".html" | Valuelist _ -> assert false | Implied_value -> "" end in if href <> "" then output_string ch ("href=\"" ^ href ^ "\""); output_string ch ">"; output_string ch (escape_html (self # node # data)); output_string ch ""; end ;; (*$-*) (*$ readme.code.footnote *) class footnote = object (self) inherit shared val mutable footnote_number = 0 method to_html store ch = let number = store # alloc_footnote (self : #shared :> footnote_printer) in let foot_anchor = "footnote" ^ string_of_int number in let text_anchor = "textnote" ^ string_of_int number in footnote_number <- number; output_string ch ( "[" ^ string_of_int number ^ "]" ) method footnote_to_html store ch = (* prerequisite: we are in a definition list
...
*) let foot_anchor = "footnote" ^ string_of_int footnote_number in let text_anchor = "textnote" ^ string_of_int footnote_number in output_string ch ("
[" ^ string_of_int footnote_number ^ "]
\n
"); List.iter (fun n -> n # extension # to_html store ch) (self # node # sub_nodes); output_string ch ("\n
") end ;; (*$-*) (**********************************************************************) (*$ readme.code.tag-map *) 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 :> shared)); "a", (new element_impl (new a)); ] () ;; (*$-*) pxp-1.2.9/examples/readme/to_text.ml0000644000175000017500000003161613055274552016070 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) open Pxp_types open Pxp_document (**********************************************************************) (* The box class represents formatted text *) (**********************************************************************) class type formatted_text = object method output : int -> int -> out_channel -> unit (* output initial_indent indent ch: * 'initial_indent' is how far the first line should be indented; * 'indent' how far the rest. 'ch' is the channel on which the lines * are to be printed. *) method multiline : bool (* whether the box occupies multiple lines *) method width_of_last_line : int (* returns the width of the last line *) end ;; type text = Text of string | Box of formatted_text ;; let textwidth tl = let rec compute tl r = match tl with [] -> r | t :: tl' -> begin match t with Text s -> compute tl' (r + String.length s) | Box b -> if b # multiline then compute tl' (b # width_of_last_line) else compute tl' (r + b # width_of_last_line) end in compute (List.rev tl) 0 ;; class box the_initial_width the_width = object (self) (* The 'initial_width' is the width that is available on the first * line of output; the 'width' is the width that is available in the * rest. *) val initial_width = the_initial_width val width = the_width (* state: *) val mutable space_added = false val mutable linefeed_added = false val mutable is_first_line = true val mutable lines = [] (* lines in reverse order (first line = last element) *) val mutable current_line = [] (* not member of 'lines'; again reverse order *) val mutable current_indent = 0 method add_space = if not space_added then begin space_added <- true; linefeed_added <- true; current_line <- Text " " :: current_line end method ignore_space = space_added <- true; linefeed_added <- true method add_linefeed = if not linefeed_added then begin linefeed_added <- true; if not space_added then current_line <- Text " " :: current_line end method ignore_linefeed = linefeed_added <- true method add_newline = lines <- current_line :: lines; current_line <- []; space_added <- true; linefeed_added <- true; is_first_line <- false; current_indent <- 0; method add_word s = (* first try to add 's' to 'current_line' *) let current_line' = Text s :: current_line in let current_width = if is_first_line then initial_width else width in if textwidth current_line' + current_indent <= current_width then begin (* ok, the line does not become too long *) current_line <- current_line'; space_added <- false; linefeed_added <- false end else begin (* The line would be too long. *) lines <- current_line :: lines; current_line <- [Text s]; space_added <- false; linefeed_added <- false; is_first_line <- false; current_indent <- 0; end method add_box b = current_line <- Box b :: current_line; space_added <- false; linefeed_added <- false; method width_of_last_line = textwidth current_line + current_indent method available_width = let current_width = if is_first_line then initial_width else width in current_width - textwidth current_line - current_indent method multiline = lines <> [] or (List.exists (function Text _ -> false | Box b -> b # multiline) current_line) method output initial_indent indent ch = let eff_lines = List.rev (current_line :: lines) in let rec out_lines cur_indent ll = match ll with [] -> () | l :: ll' -> output_string ch (String.make cur_indent ' '); List.iter (function Text s -> output_string ch s | Box b -> b # output 0 indent ch ) (List.rev l); if ll' <> [] then output_string ch "\n"; out_lines indent ll' in out_lines initial_indent eff_lines end ;; class listitem_box listmark indent totalwidth = let initial_newline = String.length listmark >= indent in object (self) inherit box totalwidth (totalwidth - indent) as super val extra_indent = indent initializer self # add_word listmark; if initial_newline then self # add_newline else begin current_line <- Text (String.make (indent - String.length listmark) ' ') :: current_line; space_added <- true; linefeed_added <- true; end method output initial_indent indent ch = super # output initial_indent (indent + extra_indent) ch end ;; (**********************************************************************) (* Footnotes etc. *) (**********************************************************************) class type footnote_printer = object method footnote_to_box : store_type -> box -> unit end and store_type = object method alloc_footnote : footnote_printer -> int method print_footnotes : box -> unit end ;; 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 <- number+1; footnotes <- footnotes @ [ number, n ]; number method print_footnotes (b : box) = if footnotes <> [] then begin b # add_newline; b # add_newline; let w = b # available_width in b # add_word (String.make (w/3) '-'); b # add_newline; b # add_newline; List.iter (fun (_,n) -> n # footnote_to_box (self : #store_type :> store_type) b) footnotes; b # add_newline; end end ;; (**********************************************************************) (* The extension objects *) (**********************************************************************) class virtual shared = object (self) (* --- default_ext --- *) val mutable node = (None : shared node option) method clone = {< >} method node = match node with None -> assert false | Some n -> n method set_node n = node <- Some n (* --- virtual --- *) method virtual to_box : store -> box -> unit (* to_box store b: * formats the element using box 'b' *) end ;; class only_data = object (self) inherit shared val white_space_re = Str.regexp "[ \t]+\\|\n" method to_box store b = let s = self # node # data in let splitted = Str.full_split white_space_re s in List.iter (function Str.Delim "\n" -> b # add_linefeed | Str.Delim _ -> b # add_space | Str.Text s -> b # add_word s) splitted end ;; class no_markup = object (self) inherit shared method to_box store b = List.iter (fun n -> n # extension # to_box store b) (self # node # sub_nodes) end ;; class readme = object (self) inherit shared method to_box store b = let title = match self # node # attribute "title" with Value s -> s | _ -> assert false in let w = b # available_width in let line = String.make (w-1) '*' in b # add_word line; b # add_newline; b # add_word title; b # add_newline; b # add_word line; b # add_newline; b # add_newline; (* process main content: *) List.iter (fun n -> n # extension # to_box store b) (self # node # sub_nodes); (* now process footnotes *) store # print_footnotes b; (* trailer *) b # add_newline; end ;; class section the_tag = object (self) inherit shared val tag = the_tag method to_box store b = let sub_nodes = self # node # sub_nodes in match sub_nodes with title_node :: rest -> b # add_newline; let w = b # available_width in let line = String.make (w-1) tag in b # add_word line; b # add_newline; b # add_word (title_node # data); b # add_newline; b # add_word line; b # add_newline; List.iter (fun n -> n # extension # to_box store b) rest; | _ -> assert false end ;; class sect1 = section '=';; class sect2 = section '-';; class sect3 = section ':';; class p = object (self) inherit shared method to_box store b = let within_list = match self # node # parent # node_type with T_element "li" -> true | T_element _ -> false | _ -> assert false in if not within_list then b # add_newline; let w = b # available_width in let b' = new box w w in b' # ignore_space; List.iter (fun n -> n # extension # to_box store b') (self # node # sub_nodes); b # add_box (b' :> formatted_text); b # add_newline; end ;; class li = object (self) inherit shared method to_box store b = b # add_newline; let w = b # available_width in let b' = new listitem_box "-" 3 w in b' # ignore_space; List.iter (fun n -> n # extension # to_box store b') (self # node # sub_nodes); b # add_box (b' :> formatted_text); end ;; class code = object (self) inherit shared method to_box store b = b # add_newline; let w = b # available_width in let b' = new box w w in b' # ignore_space; let data = self # node # data in (* convert tabs *) let l = String.length data in let rec add s i column = (* this is very ineffective but comprehensive: *) if i < l then match data.[i] with '\t' -> let n = 8 - (column mod 8) in add (s ^ String.make n ' ') (i+1) (column + n) | '\n' -> b' # add_word s; b' # add_newline; add "" (i+1) 0 | c -> add (s ^ String.make 1 c) (i+1) (column + 1) else if s <> "" then begin b' # add_word s; b' # add_newline; end in add "" 0 0; b # add_box (b' :> formatted_text); b # add_newline; end ;; class br = object (self) inherit shared method to_box store b = b # add_newline; end ;; class footnote = object (self) inherit shared val mutable footnote_number = 0 method to_box store b = let number = store # alloc_footnote (self : #shared :> footnote_printer) in footnote_number <- number; b # add_space; b # add_word ("[" ^ string_of_int number ^ "]"); method footnote_to_box store b = let w = b # available_width in let n = "[" ^ string_of_int footnote_number ^ "]" in let b' = new listitem_box n 6 w in b' # ignore_space; List.iter (fun n -> n # extension # to_box store b') (self # node # sub_nodes); b # add_box (b' :> formatted_text); b # add_newline; b # add_newline; end ;; class a = object (self) inherit shared val mutable footnote_number = 0 val mutable a_href = "" method to_box store b = let href = match self # node # attribute "href" with Value v -> "see " ^ v | Valuelist _ -> assert false | Implied_value -> begin match self # node # attribute "readmeref" with Value v -> "see file " ^ v | Valuelist _ -> assert false | Implied_value -> "" end in a_href <- href; List.iter (fun n -> n # extension # to_box store b) (self # node # sub_nodes); if href <> "" then begin let number = store # alloc_footnote (self : #shared :> footnote_printer) in footnote_number <- number; b # add_space; b # add_word ("[" ^ string_of_int number ^ "]"); end method footnote_to_box store b = if a_href <> "" then begin let w = b # available_width in let n = "[" ^ string_of_int footnote_number ^ "]" in let b' = new listitem_box n 6 w in b' # ignore_space; b' # add_word a_href; b # add_box (b' :> formatted_text); b # add_newline; b # add_newline; end end ;; (**********************************************************************) 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 no_markup)); "ul", (new element_impl (new no_markup)); "li", (new element_impl (new li)); "footnote", (new element_impl (new footnote : #shared :> shared)); "a", (new element_impl (new a : #shared :> shared)); ] () ;; pxp-1.2.9/examples/simple_transformation/0000755000175000017500000000000013055274552017223 5ustar gerdgerdpxp-1.2.9/examples/simple_transformation/Makefile0000644000175000017500000000074213055274552020666 0ustar gerdgerdall: print sort delcol print: print.ml ocamlfind ocamlc -o print -package pxp -linkpkg -custom -g \ -predicates pxp_without_utf8 print.ml sort: sort.ml ocamlfind ocamlc -o sort -package pxp -linkpkg -custom \ -predicates pxp_without_utf8 sort.ml delcol: delcol.ml ocamlfind ocamlc -o delcol -package pxp -linkpkg -custom \ -predicates pxp_without_utf8 delcol.ml clean: rm -f *.cmo *.cma *.cmi *.cmxa *.a *.o distclean: clean rm -f *~ print sort delcol CLEAN: clean pxp-1.2.9/examples/simple_transformation/README0000644000175000017500000000074613055274552020112 0ustar gerdgerdUsage: sort -by phone match n # node_type with T_element name when name = col -> raise Skip | _ -> n # orphaned_flat_clone) tree ;; let main() = let column = ref "" in Arg.parse [ "-col", Arg.String (fun s -> column := s), " (last-name|first-name|phone)"; ] (fun _ -> raise (Arg.Bad "Bad usage")) "usage: sort [ options ]"; if !column = "" then ( prerr_endline "Column not specified!"; exit 1; ); if not(List.mem !column ["last-name"; "first-name"; "phone"]) then ( prerr_endline ("Unknown column: " ^ !column); exit 1 ); try let dtd = Pxp_dtd_parser.parse_dtd_entity default_config (from_file "record.dtd") in let tree = parse_content_entity default_config (from_channel stdin) dtd default_spec in print_endline ""; (delcol !column tree) # write (`Out_channel stdout) `Enc_iso88591 with x -> prerr_endline(string_of_exn x); exit 1 ;; main();; pxp-1.2.9/examples/simple_transformation/print.ml0000644000175000017500000000174313055274552020716 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) (* Read a record-list structure and print it *) open Pxp_types;; open Pxp_document;; open Pxp_tree_parser;; let print tree = iter_tree ~pre: (fun n -> match n # node_type with T_element "last-name" -> print_endline ("Last name: " ^ n # data) | T_element "first-name" -> print_endline ("First name: " ^ n # data) | T_element "phone" -> print_endline ("Telephone number: " ^ n # data) | _ -> ()) ~post: (fun n -> match n # node_type with T_element "record" -> print_newline() | _ -> ()) tree ;; let main() = try let dtd = Pxp_dtd_parser.parse_dtd_entity default_config (from_file "record.dtd") in let tree = parse_content_entity default_config (from_channel stdin) dtd default_spec in print tree with x -> prerr_endline(string_of_exn x); exit 1 ;; main();; pxp-1.2.9/examples/simple_transformation/record.dtd0000644000175000017500000000025713055274552021202 0ustar gerdgerd pxp-1.2.9/examples/simple_transformation/sample.xml0000644000175000017500000000063013055274552021225 0ustar gerdgerd Stolpmann Gerd 997705 Smith Jack 12345 Ützgür xxx 7654 pxp-1.2.9/examples/simple_transformation/sort.ml0000644000175000017500000000303513055274552020545 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) (* Read a record-list, sort it, and print it as XML *) open Pxp_types;; open Pxp_document;; open Pxp_tree_parser;; let sort by tree = map_tree ~pre: (fun n -> n # orphaned_flat_clone) ~post: (fun n -> match n # node_type with T_element "record-list" -> let l = n # sub_nodes in let l' = List.sort (fun a b -> let a_string = try (find_element by a) # data with Not_found -> "" in let b_string = try (find_element by b) # data with Not_found -> "" in Pervasives.compare a_string b_string) l in n # set_nodes l'; n | _ -> n) tree ;; let main() = let criterion = ref "last-name" in Arg.parse [ "-by", Arg.String (fun s -> criterion := s), " (last-name|first-name|phone)"; ] (fun _ -> raise (Arg.Bad "Bad usage")) "usage: sort [ options ]"; if not(List.mem !criterion ["last-name"; "first-name"; "phone"]) then ( prerr_endline ("Unknown criterion: " ^ !criterion); exit 1 ); try let dtd = Pxp_dtd_parser.parse_dtd_entity default_config (from_file "record.dtd") in let tree = parse_content_entity default_config (from_channel stdin) dtd default_spec in print_endline ""; (sort !criterion tree) # write (`Out_channel stdout) `Enc_iso88591 with x -> prerr_endline(string_of_exn x); exit 1 ;; main();; pxp-1.2.9/examples/validate/0000755000175000017500000000000013055274552014375 5ustar gerdgerdpxp-1.2.9/examples/validate/Makefile0000644000175000017500000000341213055274552016035 0ustar gerdgerd# make validate: make bytecode executable # make validate.opt: make native executable # make clean: remove intermediate files (in this directory) # make CLEAN: remove intermediate files (recursively) # make distclean: remove any superflous files (recursively) #---------------------------------------------------------------------- # REQ: This variable is set in Makefile.config pxpvalidate: validate.ml ocamlfind ocamlc -g -o pxpvalidate -package "$(REQ)" -linkpkg validate.ml pxpvalidate.opt: validate.ml ocamlfind ocamlopt -o pxpvalidate.opt -package "$(REQ)" -linkpkg validate.ml # The following rules to create the bytecode executable assume O'Caml 3.03: pxpvalidate.byte: validate.ml ocamlfind ocamlc -o pxpvalidate.byte -package "$(REQ)" -linkpkg validate.ml pxpvalidate.1: pxpvalidate.pod pod2man --section=1 --center "www.ocaml-programming.de" --release 'PXP 1.1 tools' --lax pxpvalidate.pod >pxpvalidate.1 releasebyte: (cd ..; tar czf pxpvalidate-1.1.1.tar.gz pxpvalidate/{INSTALL,LICENSE,Makefile,pxpvalidate.1,pxpvalidate.byte,setup.sh,validate.ml}) Makefile.config: if ocamlfind query pxp-ulex-utf8 >/dev/null; then \ lexer="pxp-lex-iso88591 pxp-ulex-utf8"; \ else \ lexer="pxp-lex-iso88591 pxp-lex-utf8"; \ fi; \ echo "REQ = str pxp-engine $$lexer" >Makefile.config #---------------------------------------------------------------------- .PHONY: all all: .PHONY: clean clean: rm -f *.cmi *.cmo *.cma *.cmx *.o *.a *.cmxa .PHONY: CLEAN CLEAN: clean .PHONY: distclean distclean: clean rm -f *~ Makefile.config rm -f pxpvalidate pxpvalidate.opt pxpvalidate.byte interpreter include Makefile.config pxp-1.2.9/examples/validate/README0000644000175000017500000000214313055274552015255 0ustar gerdgerdThe pxpvalidate utility has been updated in PXP 1.1. There are a number of new options reflecting the new capabilities of the parser: -namespaces: turns namespace processing on. For a validator, this especially means that all the xmlns attributes need not to be declared. -pubid: maps a PUBLIC id to a file. Example: -pubid '-//W3C//DTD XHTML 1.0 Strict//EN=xhtml1-stict.dtd' -sysid: maps a (single) SYSTEM id to a file. Example: -sysid 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd=xhtml1-strict.dtd' This option is absolutely imperfect, because these SYSTEM IDs cannot serve as base URIs for relative URIs. If possible, PUBLIC IDs should be preferred. -helper: specifies a helper program. URIs beginning with "scheme:" are served by the specified program which must output the contents of the URI to stdout. Example: -helper 'http=wget -O - -nv' -helper-mh: another way of specifying a helper. The program must output first a MIME header, then the contents. If the MIME header contains a content-type field, the charset parameter will be evaluated. Example: -helper-mh 'http=wget -O - -s -nv' pxp-1.2.9/examples/validate/validate.ml0000644000175000017500000001373013055274552016524 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) open Pxp_document;; open Pxp_tree_parser;; open Pxp_types;; let error_happened = ref false;; let print_error e = print_endline (string_of_exn e) ;; class warner = object method warn w = print_endline ("WARNING: " ^ w) end ;; let resolve_by_helper scheme program sends_mime_header = let url_syntax = { Neturl.ip_url_syntax with Neturl.url_accepts_8bits = true } in let get_url id = (* Only accept SYSTEM Ids with the right scheme: *) match id with System sysid -> ( try let sysid_scheme = try Neturl.extract_url_scheme sysid with Neturl.Malformed_URL -> scheme (* If no scheme found: assume our own scheme *) in if sysid_scheme = scheme then Neturl.url_of_string url_syntax sysid (* or Malformed_URL *) else raise Pxp_reader.Not_competent with (* If the URL is syntactically wrong, do not accept it: *) Neturl.Malformed_URL -> raise Pxp_reader.Not_competent ) | _ -> raise Pxp_reader.Not_competent in let read_mime_header ch = let empty_re = Str.regexp "^[ \t\r\n]*$" in let is_empty s = Str.string_match empty_re s 0 in let buffer = Buffer.create 1024 in let line = ref(input_line ch) in if String.length !line >= 6 && String.sub !line 0 5 = "HTTP/" then line := input_line ch; while not (is_empty !line) do Buffer.add_string buffer !line; Buffer.add_string buffer "\n"; line := input_line ch done; Buffer.add_string buffer "\n"; Buffer.contents buffer in let open_channel id url = let url_string = Neturl.string_of_url url in let command = program ^ " " ^ Filename.quote url_string in let ch = Unix.open_process_in command in if sends_mime_header then let header_string = read_mime_header ch in let header_alist,_ = Mimestring.scan_header header_string 0 (String.length header_string) in let content_type = try List.assoc "content-type" header_alist with Not_found -> "application/octet-stream" in let mime_type, mime_type_params = Mimestring.scan_mime_type content_type [] in let encoding = try Some(Netconversion.encoding_of_string (List.assoc "charset" mime_type_params)) with Not_found -> None in ch, encoding else ch, None in let close_channel ch = match Unix.close_process_in ch with Unix.WEXITED 0 -> () | Unix.WEXITED n -> failwith("Command terminated with exit code " ^ string_of_int n) | Unix.WSIGNALED n -> failwith("Command terminated by signal " ^ string_of_int n) | _ -> assert false in new Pxp_reader.resolve_read_url_channel ~close:close_channel ~url_of_id: get_url ~channel_of_url: open_channel () ;; let parse debug wf namespaces iso88591 helpers filename = try (* Parse the document: *) let parse_fn = if wf then parse_wfdocument_entity ?transform_dtd:None else let index = new hash_index in parse_document_entity ?transform_dtd:None ~id_index:(index :> 'ext index) in let mng = if namespaces then Some (new Pxp_dtd.namespace_manager) else None in let resolver = let file_resolver = new Pxp_reader.resolve_as_file() in new Pxp_reader.combine (helpers @ [file_resolver]) in let start_id = System filename in let spec = if namespaces then default_namespace_spec else default_spec in let doc = parse_fn { default_config with debugging_mode = debug; encoding = if iso88591 then `Enc_iso88591 else `Enc_utf8; idref_pass = true; enable_namespace_processing = mng; warner = new warner } (ExtID(start_id, resolver)) spec in () with e -> (* Print error; remember that there was an error *) error_happened := true; print_error e; (* raise e *) ;; let main() = let debug = ref false in let wf = ref false in let namespaces = ref false in let iso88591 = ref false in let helpers = ref [] in let files = ref [] in let eq_split s = let eq = try String.index s '=' with Not_found -> raise(Arg.Bad "Syntax error") in let before_eq = String.sub s 0 eq in let after_eq = String.sub s (eq+1) (String.length s - eq - 1) in (before_eq, after_eq) in let add_helper sends_mime_header s = let scheme,cmd = eq_split s in let h = resolve_by_helper scheme cmd sends_mime_header in helpers := !helpers @ [h] in let add_pubid s = let pubid,filename = eq_split s in let h = Pxp_reader.lookup_public_id_as_file [pubid,filename] in helpers := !helpers @ [h] in let add_sysid s = let sysid,filename = eq_split s in let h = Pxp_reader.lookup_system_id_as_file [sysid,filename] in helpers := !helpers @ [h] in Arg.parse [ "-d", Arg.Set debug, " turn debugging mode on"; "-wf", Arg.Set wf, " check only for well-formedness"; "-namespaces", Arg.Set namespaces, " enable namespace support"; "-iso-8859-1", Arg.Set iso88591, " use ISO-8859-1 as internal encoding instead of UTF-8"; "-helper", Arg.String (add_helper false), "scheme=cmd add this helper command"; "-helper-mh", Arg.String (add_helper true), "scheme=cmd add this helper command (which sends mime headers)"; "-pubid", Arg.String add_pubid, "id=file map this PUBLIC id to this file"; "-sysid", Arg.String add_sysid, "id=file map this SYSTEM id to this file"; ] (fun x -> files := x :: !files) " usage: pxpvalidate [options] URL ... - checks the validity of XML documents. See below for list of options. PXP - The XML parser for Objective Caml List of options:"; files := List.rev !files; List.iter (parse !debug !wf !namespaces !iso88591 !helpers) !files; ;; main(); if !error_happened then exit(1);; pxp-1.2.9/examples/validate/pxpvalidate.10000644000175000017500000002714113055274552017005 0ustar gerdgerd.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "PXPVALIDATE 1" .TH PXPVALIDATE 1 "2016-03-03" "PXP 1.1 tools" "www.ocaml-programming.de" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" pxpvalidate \- validate XML documents .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBpxpvalidate\fR [ \fI\s-1OPTION\s0\fR ... ] [ \fI\s-1URL\s0\fR ... ] .SH "DESCRIPTION" .IX Header "DESCRIPTION" This command validates the \s-1XML\s0 documents specified on the command line by the \s-1XML\s0 parser \s-1PXP\s0. The program produces warning and error messages on stderr, and it exits with a non-zero code if an error is found. The program stops at the first error. If the \s-1XML\s0 documents are all valid, the program exits with a code of 0. .SS "URLs" .IX Subsection "URLs" The documents are named by their \fIURLs\fR. By default, only \f(CW\*(C`file\*(C'\fR URLs are allowed (but you can optionally configure helper applications to process other \s-1URL\s0 schemes such as \f(CW\*(C`http\*(C'\fR or \f(CW\*(C`ftp\*(C'\fR, see below). For example, to validate the file stored in \f(CW\*(C`/directory/data.xml\*(C'\fR you can call \fBpxpvalidate\fR as follows: .PP .Vb 1 \& pxpvalidate file:///directory/data.xml .Ve .PP Note that the conventions for \s-1URL\s0 notations apply: Meta characters like \&\*(L"#\*(R" or \*(L"?\*(R" are reserved and must be written using a \*(L"%hex\*(R" encoding; for instance \*(L"%23\*(R" instead of \*(L"#\*(R", or \*(L"%3f\*(R" instead of \*(L"?\*(R". .PP If you do not pass an absolute \s-1URL\s0 to \fBpxpvalidate\fR, the \s-1URL\s0 will be interpreted relative to the current directory. So .PP .Vb 2 \& cd /directory \& pxpvalidate data.xml .Ve .PP works as well. .SS "External entities" .IX Subsection "External entities" The parser reads not only the documents passed on the command line but also every other document that is referred to as an external entity. For example, if the \s-1XML\s0 document is .PP .Vb 3 \& \& ]> \& \& \& &text; \& .Ve .PP the parser reads the files \*(L"sample.dtd\*(R" and \*(L"text.xml\*(R", too, and of course further files if further entity references occur in these files. .PP The parser indicates an error if it cannot resolve a reference to an external file. .SS "Extent of the validation checks" .IX Subsection "Extent of the validation checks" The parser checks all well-formedness and validation constraints specified in the \s-1XML\s0 1.0 standard. This includes: .IP "\(bu" 4 Whether the documents are well-formed (syntactically correct) .IP "\(bu" 4 Whether the elements and attributes are used as declared, i.e. meet the \f(CW\*(C`ELEMENT\*(C'\fR and \f(CW\*(C`ATTLIST\*(C'\fR declarations. .IP "\(bu" 4 Whether the document is standalone if flagged as standalone .IP "\(bu" 4 Whether the \s-1ID\s0 attributes are unique .IP "\(bu" 4 Whether fixed attributes have the declared value .IP "\(bu" 4 Whether entities exist .IP "\(bu" 4 Whether notations exist .PP This list is not complete, see the full specification of \s-1XML\s0 1.0 for details. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-wf\fR" 4 .IX Item "-wf" The parser checks only the well-formedness of the documents, and omits any validation. .IP "\fB\-iso\-8859\-1\fR" 4 .IX Item "-iso-8859-1" The parser represents the documents internally as \s-1ISO\-8859\-1\s0 encoded strings and not as \s-1UTF\-8\s0 strings, the default. This results in faster processing if the documents are encoded in \s-1ISO\-8859\-1\s0, but it may cause problems if documents contain characters outside of the range of the \s-1ISO\-8859\-1\s0 character set. .IP "\fB\-namespaces\fR" 4 .IX Item "-namespaces" Enables the namespace support. If the \fB\-wf\fR option is turned on, too, this will only mean that element and attribute names must not contain more than one colon character. Unlike other parsers, \s-1PXP\s0 can validate documents using namespaces. See below for a discussion of this issue. .IP "\fB\-pubid\fR \fIid\fR=\fIfile\fR" 4 .IX Item "-pubid id=file" If the parser finds a \s-1PUBLIC\s0 identifier \fIid\fR, it will read the specified \fIfile\fR. (This is really a file name, and not a \s-1URL\s0.) This option overrides the system identifier found in the document for this public identifier. .Sp This option can be specified several times. .IP "\fB\-helper\fR \fIscheme\fR=\fIcommand\fR" 4 .IX Item "-helper scheme=command" Configures a helper command that gets the contents of a \s-1URL\s0 for the given \fIscheme\fR. For example, to use \fBwget\fR as helper application for ftp URLs, add the option .Sp .Vb 1 \& \-helper \*(Aqftp=wget \-O \- \-nv\*(Aq .Ve .Sp The command is expected to output the contents of the file to stdout. .Sp This option can be specified several times. .IP "\fB\-helper\-mh\fR \fIscheme\fR=\fIcommand\fR" 4 .IX Item "-helper-mh scheme=command" Configures a helper command that gets the contents of a \s-1URL\s0 for the given \fIscheme\fR. For example, to use \fBwget\fR as helper application for http URLs, add the option .Sp .Vb 1 \& \-helper\-mh \*(Aqhttp=wget \-O \- \-nv \-s\*(Aq .Ve .Sp The command is expected to output first a \s-1MIME\s0 header and then, separated by a blank line, the contents of the file to stdout. .Sp Using \fB\-helper\-mh\fR is preferred if \s-1MIME\s0 headers are available. The parser extracts the character encoding of the file from the \s-1MIME\s0 header. .Sp This option can be specified several times. .SH "ENCODINGS" .IX Header "ENCODINGS" .SS "The character encoding of URLs" .IX Subsection "The character encoding of URLs" URLs are interpreted as \*(L"%\-encoded \s-1UTF\-8\s0 strings\*(R", as suggested by the \&\s-1XML\s0 standard. .SS "The character encoding of filenames" .IX Subsection "The character encoding of filenames" The parser assumes that the file system stores filenames as \s-1UTF\-8\s0 strings. (Sorry, it is currently not possible to change this.) .SS "The encodings of entities" .IX Subsection "The encodings of entities" Every external entity can be encoded in a different character set. A document can refer to entities that are encoded differently. The parser supports \s-1UTF\-8\s0, \s-1UTF\-16\s0, \s-1UTF\-32\s0, all \s-1ISO\-8859\s0 encodings, and a list of other 8 bit character set. .SH "VALIDATION AND NAMESPACES" .IX Header "VALIDATION AND NAMESPACES" \&\s-1PXP\s0 can validate documents that use namespaces. However, it is necessary to add processing instructions to the \s-1DTD\s0 because the \s-1XML\s0 standard does not specify how to refer to namespaces in DTDs. .PP It is quite simple. The processing instruction .PP .PP declares that the namespace \fIuri\fR can be referred to from the \s-1DTD\s0 by prefixing element and attribute names by the string \fIprefix\fR, followed by a colon character. For example, to define the prefix \&\f(CW\*(C`xh\*(C'\fR for the \s-1XHTML\s0 \s-1URI\s0 \f(CW\*(C`http://www.w3.org/1999/xhtml\*(C'\fR just add the line .PP .Vb 1 \& .Ve .PP to the \s-1DTD\s0, and prepend the prefix \*(L"xh:\*(R" to the names of all elements in the \s-1DTD\s0 (e.g. \*(L"xh:body\*(R" instead of \*(L"body\*(R"). .PP If the author of the \s-1XHTML\s0 document prefers another prefix, \s-1PXP\s0 automatically converts the other prefix to the declared prefix \*(L"xh\*(R": .PP .Vb 3 \& \& ... \& .Ve .PP Note that if you do not declare the namespaces in the \s-1DTD\s0, the parser will use the first used prefix for a namespace as the reference prefix, and it will take this prefix to match the element names in the document with the element names in the \s-1DTD\s0. This may cause problems. .SH "AUTHOR" .IX Header "AUTHOR" The parser \s-1PXP\s0 and the frontend \fBpxpvalidate\fR have been written by Gerd Stolpmann (gerd@gerd\-stolpmann.de). .SH "WEB SITE" .IX Header "WEB SITE" The sources are published on the web site http://www.ocaml\-programming.de. You will find there also material about the programming language Objective Caml (in which \s-1PXP\s0 is written). pxp-1.2.9/examples/xmlforms/0000755000175000017500000000000013055274552014453 5ustar gerdgerdpxp-1.2.9/examples/xmlforms/Makefile0000644000175000017500000000140713055274552016115 0ustar gerdgerd# make xmlforms: make bytecode executable # make xmlforms.opt: make native executable # make clean: remove intermediate files # make CLEAN: remove intermediate files (recursively) # make distclean: remove any superflous files # make release: cleanup, create archive, tag CVS module # (for developers) #---------------------------------------------------------------------- .PHONY: xmlforms xmlforms: $(MAKE) -f Makefile.code xmlforms .PHONY: xmlforms.opt xmlforms.opt: $(MAKE) -f Makefile.code xmlforms.opt .PHONY: clean clean: rm -f *.cmi *.cmo *.cma *.cmx *.o *.a *.cmxa .PHONY: CLEAN CLEAN: clean $(MAKE) -C styles CLEAN .PHONY: distclean distclean: clean rm -f *~ depend depend.pkg rm -f xmlforms xmlforms.opt $(MAKE) -C styles distclean pxp-1.2.9/examples/xmlforms/Makefile.code0000644000175000017500000000221013055274552017017 0ustar gerdgerd#---------------------------------------------------------------------- # specific rules for this package: OBJECTS = ds_context.cmo ds_style.cmo XOBJECTS = $(OBJECTS:.cmo=.cmx) ARCHIVE = xmlforms.cma XARCHIVE = xmlforms.cmxa NAME = xmlforms REQUIRES = labltk str pxp xmlforms: $(ARCHIVE) ds_app.cmo ocamlfind ocamlc -g -o xmlforms -package "$(REQUIRES)" \ -linkpkg $(ARCHIVE) ds_app.cmo xmlform.opt: $(XARCHIVE) ds_app.cmx ocamlfind ocamlopt -o xmlforms.opt -package "$(REQUIRES)" \ -linkpkg $(XARCHIVE) ds_app.cmx $(ARCHIVE): $(OBJECTS) $(OCAMLC) -a -o $(ARCHIVE) $(OBJECTS) $(XARCHIVE): $(XOBJECTS) $(OCAMLOPT) -a -o $(XARCHIVE) $(XOBJECTS) #---------------------------------------------------------------------- # general rules: OPTIONS = OCAMLC = ocamlfind ocamlc -g -package "$(REQUIRES)" OCAMLOPT = ocamlfind ocamlopt -package "$(REQUIRES)" OCAMLDEP = ocamldep $(OPTIONS) OCAMLFIND = ocamlfind depend: *.ml *.mli $(OCAMLDEP) *.ml *.mli >depend .SUFFIXES: .cmo .cmi .cmx .ml .mli .mll .mly .ml.cmx: $(OCAMLOPT) -c $< .ml.cmo: $(OCAMLC) -c $< .mli.cmi: $(OCAMLC) -c $< .mll.ml: ocamllex $< *.mli: include depend pxp-1.2.9/examples/xmlforms/README0000644000175000017500000000425613055274552015342 0ustar gerdgerd----------------------------------------------------------------------------- xmlforms ----------------------------------------------------------------------------- THE IDEA: This example uses XML for two purposes: - The "story" and layout of the application is specified in XML - The data records are stored in XML An "application" is a set of "masks" or sequences of masks, and every mask is thought as a visible page of the application, containing layout elements and functional elements. Layout is specified in TeX-style using hboxes, vboxes, hspaces, vspaces. Functional elements are "entries" (input box for a string with one line), "textboxes" (input boxes with several lines), and buttons. See styles/ds-style.dtd for the DTD of an application specification, and the other xml files in this directory for examples. The entries and textboxes are bound to "slots", i.e. string variables. If the application is started, the slots are read from a file, and if the user presses a special "save" button, the slots are stored into this file. The format of this data file is again XML; the simplistic DTD can be found in styles/ds-object.dtd. THE IMPLEMENTATION: There is currently a mapping of the specifications to ocamltk, done by a program called "xmlforms". HOW TO COMPILE: It is assumed that "findlib" is present on your system; see ABOUT-FINDLIB in the toplevel directory. The "markup" module must have been installed. - "make xmlforms" produces a bytecode executable "xmlforms" - "make xmlforms.opt" produces a native executable "xmlforms.opt" Note that you cannot start the executables directly: HOW TO START AN APPLICATION: As "xmlforms" is a generic executable, there is a simple mechanism to bind it to a specific instance of an application. For example, in the "styles" subdirectory there is the application specification "crazy-style.xml". To start it, make a symlink called "crazy" referring to the "xmlforms" binary, set the environment variable DATASHEETS to the directory where the DTDs and XML files can be found, and start "crazy": ln -s ../xmlforms crazy DATASHEETS=. crazy my-record.xml (If you do not set DATASHEETS, a default directory, normally "/opt/xmlforms/lib" is used.) pxp-1.2.9/examples/xmlforms/ds_app.ml0000644000175000017500000000332013055274552016251 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) open Tk open Pxp_types open Pxp_document open Pxp_tree_parser open Ds_context open Ds_style let installdir = try Sys.getenv "DATASHEETS" with Not_found -> "/opt/xmlforms/lib" let style_sysid = ref "" let object_dtd_sysid = Filename.concat installdir "ds-object.dtd" let object_dtd_root = "record" let rec print_error e = print_endline (string_of_exn e) ;; let run f arg1 arg2 = try f arg1 arg2 with e -> print_error e ;; let edit filename cmd = (* read in style definition *) let index = new hash_index in let style = parse_document_entity ~id_index:(index :> 'ext index) default_config (from_file !style_sysid) tag_map in let root = style # root in root # extension # prepare (index :> 'ext index); let obj_dtd = Pxp_dtd_parser.parse_dtd_entity default_config (from_file object_dtd_sysid) in obj_dtd # set_root object_dtd_root; let topframe = openTk() in let topframe_frame = Frame.create ~borderwidth:0 topframe in let context = new context filename obj_dtd index root topframe_frame in Toplevel.configure ~width:(Tk.pixels (`Cm 20.0)) ~height:(Tk.pixels (`Cm 12.0)) topframe; Pack.propagate_set topframe false; Wm.title_set topframe cmd; pack [topframe_frame]; context # goto (root # extension # start_node_name); mainLoop() ;; let main() = let cmd = Filename.basename Sys.argv.(0) in match Sys.argv with [| _; filename |] -> style_sysid := Filename.concat installdir (cmd ^ "-style.xml"); run edit filename cmd | _ -> prerr_endline ("usage: " ^ cmd ^ " filename"); exit(1) ;; main();; pxp-1.2.9/examples/xmlforms/ds_context.ml0000644000175000017500000000733213055274552017164 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) open Pxp_types open Pxp_document open Pxp_tree_parser let empty_record = new element_impl (Pxp_yacc.default_extension);; let empty_dnode = new data_impl Pxp_yacc.default_extension;; class context the_filename the_obj_dtd the_index the_root the_topframe = object (self) val filename = the_filename val obj_dtd = the_obj_dtd val node_index = the_index val mutable obj = empty_record # create_element the_obj_dtd (T_element "record") [] val root = the_root val topframe = the_topframe val mutable wdg = None val mutable history = ( [| |] : string array ) val mutable index = 0 initializer self # load_obj method obj = obj (* history *) method private leave_node = begin match wdg with None -> () | Some w -> Tk.destroy w end; wdg <- None method private enter_node = let where = history.(index) in let n = try node_index # find where with Not_found -> failwith ("Mask not found: " ^ where) in let w = n # extension # create_widget topframe self in (* Tk.pack [w] (n # extension # pack_opts @ [ Tk.Expand true] ); *) (*X*) n # extension # pack ?expand:(Some true) ?anchor:None ?fill:None ?side:None [Widget.forget_type w]; wdg <- Some w method previous = if index > 0 then index <- index - 1 else raise Not_found; self # leave_node; self # enter_node; method next = if index < Array.length history - 1 then index <- index + 1 else raise Not_found; self # leave_node; self # enter_node; method goto where = assert (index <= Array.length history); self # leave_node; let persisting_history = if index < Array.length history then Array.sub history 0 (index+1) else history in history <- Array.concat [ persisting_history; [| where |] ]; index <- Array.length history - 1; self # enter_node; method current = if index < Array.length history then history.(index) else raise Not_found (* read, write the slots of object *) method search_slot name = let rec search n = match n # node_type with T_element "string" -> if n # required_string_attribute "name" = name then n else raise Not_found | T_element _ -> search_list (n # sub_nodes) | T_data -> raise Not_found | _ -> assert false and search_list l = match l with x :: l' -> (try search x with Not_found -> search_list l') | [] -> raise Not_found in search obj method get_slot name = let d = (self # search_slot name) # data in d method set_slot name value = let dtd = obj # dtd in begin try let n = self # search_slot name in n # delete with Not_found -> () end; let e_string = empty_record # create_element dtd (T_element "string") [ "name", name ] in let dnode = empty_dnode # create_data dtd value in e_string # add_node dnode; e_string # local_validate(); obj # add_node e_string; assert(self # get_slot name = value) (* load, save object *) method load_obj = if Sys.file_exists filename then begin obj <- parse_content_entity default_config (from_file filename) obj_dtd default_spec end else begin print_string "New file!\n"; flush stdout end method save_obj = let fd = open_out filename in try output_string fd "\n"; obj # write (`Out_channel fd) `Enc_iso88591; close_out fd with e -> close_out fd; raise e end ;; pxp-1.2.9/examples/xmlforms/ds_style.ml0000644000175000017500000004716713055274552016652 0ustar gerdgerd(* $Id$ * ---------------------------------------------------------------------- * *) open Pxp_types open Pxp_document open Ds_context let get_dimension s = let re = Str.regexp "\\([0-9]*\\(.[0-9]+\\)?\\)[ \t\n]*\\(px\\|cm\\|in\\|mm\\|pt\\)" in if Str.string_match re s 0 then begin let number = Str.matched_group 1 s in let dim = Str.matched_group 3 s in match dim with "px" -> `Pix (int_of_float (float_of_string number)) | "cm" -> `Cm (float_of_string number) | "in" -> `In (float_of_string number) | "mm" -> `Mm (float_of_string number) | "pt" -> `Pt (float_of_string number) | _ -> assert false end else failwith ("Bad dimension: " ^ s) ;; class virtual shared = object(self) (* --- default_ext --- *) val mutable node = (None : shared node option) method clone = {< >} method node = match node with None -> assert false | Some n -> n method set_node n = node <- Some n (* --- shared attributes: color & font settings --- *) val mutable fgcolor = (None : string option) val mutable bgcolor = (None : string option) val mutable font = (None : string option) method fgcolor = (* Get the foreground color: If there is a local value, return it; * otherwise ask parent node *) match fgcolor with Some c -> c | None -> try self # node # parent # extension # fgcolor with Not_found -> failwith "#fgcolor" method bgcolor = (* Get the background color: If there is a local value, return it; * otherwise ask parent node *) match bgcolor with Some c -> c | None -> try self # node # parent # extension # bgcolor with Not_found -> failwith "#bgcolor" method font = (* Get the current font: If there is a local value, return it; * otherwise ask parent node *) match font with Some c -> c | None -> try self # node # parent # extension # font with Not_found -> failwith "#font" method private init_color_and_font = let get_color n = try match self # node # attribute n with Value v -> Some v | Implied_value -> None | _ -> assert false with Not_found -> None in fgcolor <- get_color "fgcolor"; bgcolor <- get_color "bgcolor"; font <- get_color "font"; (* sic! *) method private bg_color_opt = `Color (self # bgcolor) method private fg_color_opt = `Color (self # fgcolor) (* --- virtual --- *) method virtual prepare : shared Pxp_yacc.index -> unit method virtual create_widget : Widget.frame Widget.widget -> context -> Widget.any Widget.widget method pack ?expand ?anchor ?fill ?side (wl : Widget.any Widget.widget list) = Tk.pack ?expand ?anchor ?fill ?side wl method xstretchable = false method ystretchable = false method accept (c:context) = () method private get_mask = (* find parent which is a mask *) let rec search n = match n # node_type with T_element "mask" -> n # extension | T_element _ -> search (n # parent) | _ -> assert false in search (self # node) method private accept_mask (c:context) = let rec iterate n = n # extension # accept c; List.iter iterate (n # sub_nodes) in iterate (self # get_mask # node) method start_node_name = (failwith "#start_node_name" : string) (* --- debug --- *) method private name = let nt = self # node # node_type in match nt with T_element n -> n | T_data -> "#PCDATA" | _ -> assert false end ;; class default = object (self) inherit shared method prepare idx = self # init_color_and_font method create_widget w c = failwith "default # create_widget" end ;; let dummy_node = new element_impl (new default);; class application = object (self) inherit shared val mutable start_node = dummy_node method prepare idx = (* prepare this node *) self # init_color_and_font; if fgcolor = None then fgcolor <- Some "black"; if bgcolor = None then bgcolor <- Some "white"; if font = None then font <- Some "fixed"; let start = match self # node # attribute "start" with Value v -> v | _ -> assert false in start_node <- (try idx # find start with Not_found -> failwith "Start node not found"); (* iterate over the subtree *) let rec iterate n = n # extension # prepare idx; List.iter iterate (n # sub_nodes) in List.iter iterate (self # node # sub_nodes) method start_node_name = match self # node # attribute "start" with Value v -> v | _ -> assert false method create_widget w c = start_node # extension # create_widget w c method pack ?expand ?anchor ?fill ?side wl = start_node # extension # pack ?expand ?anchor ?fill ?side wl end ;; class sequence = object (self) inherit shared method prepare idx = self # init_color_and_font; method create_widget w c = let node = List.hd (self # node # sub_nodes) in node # extension # create_widget w c method pack ?expand ?anchor ?fill ?side wl = let node = List.hd (self # node # sub_nodes) in node # extension # pack ?expand ?anchor ?fill ?side wl end ;; class vbox = object (self) inherit shared val mutable att_halign = "left" method prepare idx = self # init_color_and_font; match self # node # attribute "halign" with Value v -> att_halign <- v | _ -> assert false method create_widget w c = let f = Frame.create ~background:(self # bg_color_opt) w in let nodes = self # node # sub_nodes in let anchor = match att_halign with "left" -> `W | "right" -> `E | "center" -> `Center | _ -> assert false in List.iter (fun n -> let wdg = n # extension # create_widget f c in (n # extension : shared) # pack ~anchor [Widget.forget_type wdg] ) nodes; Widget.forget_type f method pack ?expand ?anchor ?fill ?side wl = let fill' = match self # xstretchable, self # ystretchable with true, false -> `X; (* Tk.Expand true *) | false, true -> `Y; (* Tk.Expand true *) | true, true -> `Both; (* Tk.Expand true *) | false, false -> `None in Tk.pack ?expand ?anchor ~fill:fill' ?side wl method xstretchable = let nodes = self # node # sub_nodes in List.exists (fun n -> n # extension # xstretchable) nodes method ystretchable = let nodes = self # node # sub_nodes in List.exists (fun n -> n # extension # ystretchable) nodes end ;; class mask = object (self) inherit vbox method prepare idx = self # init_color_and_font; att_halign <- "left" end ;; class hbox = object (self) inherit shared val mutable att_width = None val mutable att_halign = "left" val mutable att_valign = "top" method prepare idx = self # init_color_and_font; begin match self # node # attribute "halign" with Value v -> att_halign <- v | _ -> assert false end; begin match self # node # attribute "valign" with Value v -> att_valign <- v | _ -> assert false end; begin match self # node # attribute "width" with Value v -> att_width <- Some (get_dimension v) | Implied_value -> att_width <- None | _ -> assert false end method create_widget w c = let f1 = Frame.create ~background:(self # bg_color_opt) w in let f_extra = match att_width with None -> None | Some wd -> Some (Canvas.create ~width:(Tk.pixels wd) ~height:0 ~relief:`Flat ~highlightthickness:0 ~background:(self # bg_color_opt) f1 ) in let f2 = Frame.create ~background:(self # bg_color_opt) f1 in let nodes = self # node # sub_nodes in let outer_pack_anchor = match att_halign with "left" -> `W | "right" -> `E | "center" -> `Center | _ -> assert false in let inner_pack_anchor = match att_valign with "top" -> `N | "bottom" -> `S | "center" -> `Center | _ -> assert false in List.iter (fun n -> let wdg = n # extension # create_widget f2 c in (n # extension : shared) # pack ~anchor:inner_pack_anchor ~side:`Left [Widget.forget_type wdg]; ) nodes; ( match f_extra with Some wdg -> self # pack ~anchor:outer_pack_anchor [Widget.forget_type wdg]; | None -> () ); self # pack ~anchor:outer_pack_anchor [Widget.forget_type f2]; Widget.forget_type f1 method pack ?expand ?anchor ?fill ?side wl = let fill' = match self # xstretchable, self # ystretchable with true, false -> `X (* Tk.Expand true *) | false, true -> `Y (* Tk.Expand true *) | true, true -> `Both (* Tk.Expand true *) | false, false -> `None in Tk.pack ?expand ?anchor ~fill:fill' ?side wl method xstretchable = let nodes = self # node # sub_nodes in List.exists (fun n -> n # extension # xstretchable) nodes method ystretchable = let nodes = self # node # sub_nodes in List.exists (fun n -> n # extension # ystretchable) nodes end ;; class vspace = object (self) inherit shared val mutable att_height = `Pix 0 val mutable att_fill = false method prepare idx = self # init_color_and_font; begin match self # node # attribute "height" with Value v -> att_height <- get_dimension v | _ -> assert false end; begin match self # node # attribute "fill" with Value "yes" -> att_fill <- true | Value "no" -> att_fill <- false | _ -> assert false end method create_widget w c = let f = Frame.create ~background:( self # bg_color_opt ) w in let strut = Canvas.create ~height:(Tk.pixels att_height) ~width:0 ~relief:`Flat ~highlightthickness:0 ~background:( self # bg_color_opt ) f in if att_fill then Tk.pack ~fill:`Y ~expand:true [strut] else Tk.pack [strut]; Widget.forget_type f method pack ?expand ?anchor ?fill ?side wl = if att_fill then Tk.pack ~fill:`Y ~expand:true ?anchor ?side wl else Tk.pack ?fill ?expand ?anchor ?side wl method ystretchable = att_fill end ;; class hspace = object (self) inherit shared val mutable att_width = `Pix 0 val mutable att_fill = false method prepare idx = self # init_color_and_font; begin match self # node # attribute "width" with Value v -> att_width <- get_dimension v | _ -> assert false end; begin match self # node # attribute "fill" with Value "yes" -> att_fill <- true | Value "no" -> att_fill <- false | _ -> assert false end method create_widget w c = let f = Frame.create ~background:( self # bg_color_opt ) w in let strut = Canvas.create ~width:(Tk.pixels att_width) ~height:0 ~relief:`Flat ~highlightthickness:0 ~background:( self # bg_color_opt ) f in if att_fill then Tk.pack ~fill:`X ~expand:true [strut] else Tk.pack [strut]; Widget.forget_type f method pack ?expand ?anchor ?fill ?side wl = if att_fill then Tk.pack ~fill:`X ~expand:true ?anchor ?side wl else Tk.pack ?fill ?expand ?anchor ?side wl method xstretchable = att_fill end ;; class label = object (self) inherit shared val mutable att_textwidth = (-1) val mutable att_halign = "left" method prepare idx = self # init_color_and_font; att_textwidth <- (match self # node # attribute "textwidth" with Value v -> let w = try int_of_string v with _ -> failwith ("Not an integer: " ^ v) in w | Implied_value -> (-1) | _ -> assert false); att_halign <- (match self # node # attribute "halign" with Value v -> v | _ -> assert false); method create_widget w c = let opts_textwidth = if att_textwidth < 0 then None else Some att_textwidth in let opts_anchor = match att_halign with "left" -> `W | "right" -> `E | "center" -> `Center | _ -> assert false in let opts_content = self # node # data in let label = Label.create ?width:opts_textwidth ~anchor:opts_anchor ~text:opts_content ~background:(self # bg_color_opt) ~foreground:(self # fg_color_opt) ~font:(self # font) w in Widget.forget_type label end ;; class entry = object (self) inherit shared val mutable tv = lazy (Textvariable.create()) val mutable att_textwidth = (-1) val mutable att_slot = "" method prepare idx = self # init_color_and_font; tv <- lazy (Textvariable.create()); att_textwidth <- (match self # node # attribute "textwidth" with Value v -> let w = try int_of_string v with _ -> failwith ("Not an integer: " ^ v) in w | Implied_value -> (-1) | _ -> assert false); att_slot <- (match self # node # attribute "slot" with Value v -> v | _ -> assert false); method create_widget w c = let opts_textwidth = if att_textwidth < 0 then None else Some att_textwidth in let e = Entry.create ~textvariable:(Lazy.force tv) ~foreground:(self # fg_color_opt) ~background:(self # bg_color_opt) ~font:(self # font) ?width:opts_textwidth w in let s = try c # get_slot att_slot with Not_found -> self # node # data in Textvariable.set (Lazy.force tv) s; Widget.forget_type e method accept c = c # set_slot att_slot (Textvariable.get (Lazy.force tv)) end ;; class textbox = object (self) inherit shared val mutable att_textwidth = (-1) val mutable att_textheight = (-1) val mutable att_slot = "" val mutable last_widget = None method prepare idx = self # init_color_and_font; att_textwidth <- (match self # node # attribute "textwidth" with Value v -> let w = try int_of_string v with _ -> failwith ("Not an integer: " ^ v) in w | Implied_value -> (-1) | _ -> assert false); att_textheight <- (match self # node # attribute "textheight" with Value v -> let w = try int_of_string v with _ -> failwith ("Not an integer: " ^ v) in w | Implied_value -> (-1) | _ -> assert false); att_slot <- (match self # node # attribute "slot" with Value v -> v | Implied_value -> "" | _ -> assert false); method create_widget w c = let opts_textwidth = if att_textwidth < 0 then None else Some att_textwidth in let opts_textheight = if att_textheight < 0 then None else Some att_textheight in let f = Frame.create ~background:(self # bg_color_opt) w in let vscrbar = Scrollbar.create ~orient:`Vertical f in let e = Text.create ~foreground:(self # fg_color_opt) ~background:(self # bg_color_opt) ~font:(self # font) ?width:opts_textwidth ?height:opts_textheight f in last_widget <- Some e; Scrollbar.configure ~command:(fun ~scroll:s -> Text.yview e s) ~width:9 vscrbar; Text.configure ~yscrollcommand:(fun ~first:a ~last:b -> Scrollbar.set vscrbar a b) e; let s = if att_slot <> "" then try c # get_slot att_slot with Not_found -> self # node # data else self # node # data in (* Text.insert appends always a newline to the last line; so strip * an existing newline first *) let s' = if s <> "" & s.[String.length s - 1] = '\n' then String.sub s 0 (String.length s - 1) else s in Text.insert ~index:(`End,[]) ~text:s' e; if att_slot = "" then Text.configure ~state:`Disabled e; Tk.pack ~side:`Left [e]; Tk.pack ~side:`Left ~fill:`Y [vscrbar]; Widget.forget_type f method accept c = if att_slot <> "" then match last_widget with None -> () | Some w -> let s = Text.get w ~start:(`Linechar(1,0), []) ~stop:(`End,[]) in c # set_slot att_slot s end ;; class button = object (self) inherit shared val mutable att_label = "" val mutable att_action = "" val mutable att_goto = "" method prepare idx = self # init_color_and_font; att_label <- (match self # node # attribute "label" with Value v -> v | _ -> assert false); att_action <- (match self # node # attribute "action" with Value v -> v | _ -> assert false); att_goto <- (match self # node # attribute "goto" with Value v -> v | Implied_value -> "" | _ -> assert false); if att_action = "goto" then begin try let _ = idx # find att_goto in () with Not_found -> failwith ("Target `" ^ att_goto ^ "' not found") end; if att_action = "list-prev" or att_action = "list-next" then begin let m = self # get_mask in if m # node # parent # node_type <> T_element "sequence" then failwith ("action " ^ att_action ^ " must not be used out of "); end; method create_widget w c = let cmd () = self # accept_mask c; match att_action with "goto" -> c # goto att_goto | "save" -> c # save_obj | "exit" -> Protocol.closeTk() | "save-exit" -> c # save_obj; Protocol.closeTk() | "list-prev" -> let m = self # get_mask # node in let s = m # parent in let rec search l = match l with x :: y :: l' -> if y == m then match x # attribute "name" with Value s -> c # goto s | _ -> assert false else search (y :: l') | _ -> () in search (s # sub_nodes) | "list-next" -> let m = self # get_mask # node in let s = m # parent in let rec search l = match l with x :: y :: l' -> if x == m then match y # attribute "name" with Value s -> c # goto s | _ -> assert false else search (y :: l') | _ -> () in search (s # sub_nodes) | "hist-prev" -> (try c # previous with Not_found -> ()) | "hist-next" -> (try c # next with Not_found -> ()) | _ -> () in let b = Button.create ~text:att_label ~command:cmd ~foreground:(self # fg_color_opt) ~background:(self # bg_color_opt) ~font:(self # font) w in Widget.forget_type b end ;; (**********************************************************************) open Pxp_yacc let tag_map = make_spec_from_mapping ~data_exemplar:(new data_impl (new default)) ~default_element_exemplar:(new element_impl (new default)) ~element_mapping: (let m = Hashtbl.create 50 in Hashtbl.add m "application" (new element_impl (new application)); Hashtbl.add m "sequence" (new element_impl (new sequence)); Hashtbl.add m "mask" (new element_impl (new mask)); Hashtbl.add m "vbox" (new element_impl (new vbox)); Hashtbl.add m "hbox" (new element_impl (new hbox)); Hashtbl.add m "vspace" (new element_impl (new vspace)); Hashtbl.add m "hspace" (new element_impl (new hspace)); Hashtbl.add m "label" (new element_impl (new label)); Hashtbl.add m "entry" (new element_impl (new entry)); Hashtbl.add m "textbox" (new element_impl (new textbox)); Hashtbl.add m "button" (new element_impl (new button)); m) () ;; pxp-1.2.9/examples/xmlforms/styles/0000755000175000017500000000000013055274552015776 5ustar gerdgerdpxp-1.2.9/examples/xmlforms/styles/Makefile0000644000175000017500000000033013055274552017432 0ustar gerdgerd.PHONY: all all: .PHONY: clean clean: .PHONY: CLEAN CLEAN: clean .PHONY: distclean distclean: clean rm -f *~ .PHONY: symlinks symlinks: for x in *-style.xml; do ln -s ../xmlforms $${x%-style.xml} || true; done pxp-1.2.9/examples/xmlforms/styles/address-style.xml0000644000175000017500000002466413055274552021317 0ustar gerdgerd '> '> '>