(* * Xml Light, an small Xml parser/printer with DTD support. * Copyright (C) 2003 Nicolas Cannasse (ncannasse@motion-twin.com) * Copyright (C) 2003 Jacques Garrigue * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)
open Printf open Xml_datatype
type xml = Xml_datatype.xml
type error_pos = {
eline : int;
eline_start : int;
emin : int;
emax : int;
}
type t = {
mutable check_eof : bool;
mutable concat_pcdata : bool;
source : Lexing.lexbuf;
stack : Xml_lexer.token Stack.t;
}
type source =
| SChannel of in_channel
| SString ofstring
| SLexbuf of Lexing.lexbuf
exception Internal_error of error_msg
exception NoMoreData
let xml_error = ref (fun _ -> assert false) let file_not_found = ref (fun _ -> assert false)
let is_blank s = let len = String.length s in let break = reftruein let i = ref 0 in while !break && !i < len do let c = s.[!i] in (* no '\r' because we replaced them in the lexer *) if c = ' ' || c = '\n' || c = '\t'then incr i else break := false
done;
!i = len
let _raises e f =
xml_error := e;
file_not_found := f
let make source = let source = match source with
| SChannel chan -> Lexing.from_channel chan
| SString s -> Lexing.from_string s
| SLexbuf lexbuf -> lexbuf in let () = Xml_lexer.init source in
{
check_eof = false;
concat_pcdata = true;
source = source;
stack = Stack.create ();
}
let check_eof p v = p.check_eof <- v
let pop s = try
Stack.pop s.stack with
Stack.Empty ->
Xml_lexer.token s.source
let push t s =
Stack.push t s.stack
let canonicalize_elts l = let has_elt = List.exists (function Element _ -> true | _ -> false) l in if has_elt thenList.filter (function PCData s -> not (is_blank s) | _ -> true) l else l
let rec read_xml canonicalize s = let rec read_node s = match pop s with
| Xml_lexer.PCData s -> PCData s
| Xml_lexer.Tag (tag, attr, true) -> Element (tag, attr, [])
| Xml_lexer.Tag (tag, attr, false) -> let elements = read_elems tag s in let elements = if canonicalize then canonicalize_elts elements else elements in
Element (tag, attr, elements)
| t ->
push t s; raise NoMoreData
and read_elems tag s = let elems = ref [] in
(try whiletruedo let node = read_node s in match node, !elems with
| PCData c , (PCData c2) :: q ->
elems := PCData (c2 ^ c) :: q
| _, l ->
elems := node :: l
done with
NoMoreData -> ()); match pop s with
| Xml_lexer.Endtag s when s = tag -> List.rev !elems
| t -> raise (Internal_error (EndOfTagExpected tag)) in match read_node s with
| (Element _) as node ->
node
| PCData c -> if is_blank c then
read_xml canonicalize s else raise (Xml_lexer.Error Xml_lexer.ENodeExpected)
let error_of_exn xparser = function
| NoMoreData when pop xparser = Xml_lexer.Eof -> Empty
| NoMoreData -> NodeExpected
| Internal_error e -> e
| Xml_lexer.Error e -> convert e
| e -> (*let e = Errors.push e in: We do not record backtrace here. *) raise e
let do_parse canonicalize xparser = try
Xml_lexer.init xparser.source; let x = read_xml canonicalize xparser in if xparser.check_eof && pop xparser <> Xml_lexer.Eof thenraise (Internal_error EOFExpected);
Xml_lexer.close ();
x with any ->
Xml_lexer.close (); raise (!xml_error (error_of_exn xparser any) xparser.source)
let parse ?(canonicalize=true) p =
do_parse canonicalize p
let error_msg = function
| UnterminatedComment -> "Unterminated comment"
| UnterminatedString -> "Unterminated string"
| UnterminatedEntity -> "Unterminated entity"
| IdentExpected -> "Ident expected"
| CloseExpected -> "Element close expected"
| NodeExpected -> "Xml node expected"
| AttributeNameExpected -> "Attribute name expected"
| AttributeValueExpected -> "Attribute value expected"
| EndOfTagExpected tag -> sprintf "End of tag expected : '%s'" tag
| EOFExpected -> "End of file expected"
| Empty -> "Empty"
let error (msg,pos) = if pos.emin = pos.emax then
sprintf "%s line %d character %d" (error_msg msg) pos.eline
(pos.emin - pos.eline_start) else
sprintf "%s line %d characters %d-%d" (error_msg msg) pos.eline
(pos.emin - pos.eline_start) (pos.emax - pos.eline_start)
let line e = e.eline
let range e =
e.emin - e.eline_start , e.emax - e.eline_start
let abs_range e =
e.emin , e.emax
let pos source = let line, lstart, min, max = Xml_lexer.pos source in
{
eline = line;
eline_start = lstart;
emin = min;
emax = max;
}
let () = _raises (fun x p -> (* local cast : Xml.error_msg -> error_msg *)
Error (x, pos p))
(fun f -> File_not_found f)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.