mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-06-06 07:53:43 +08:00
a9d144d583
add subst_or_add_child
277 lines
7.9 KiB
OCaml
277 lines
7.9 KiB
OCaml
(*
|
|
* $Id$
|
|
*
|
|
* Xml-Light extension
|
|
*
|
|
* Copyright (C) 2004 CENA/ENAC, Pascal Brisset
|
|
*
|
|
* This file is part of paparazzi.
|
|
*
|
|
* paparazzi is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* paparazzi 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with paparazzi; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*
|
|
*)
|
|
|
|
open Printf
|
|
|
|
exception Error of string
|
|
|
|
let sep = Str.regexp "\\."
|
|
|
|
let child xml ?select c =
|
|
let rec find = function
|
|
Xml.Element (tag, _attributes, _children) as elt :: elts ->
|
|
if tag = c then
|
|
match select with
|
|
None -> elt
|
|
| Some p ->
|
|
if p elt then elt else find elts
|
|
else
|
|
find elts
|
|
| _ :: elts -> find elts
|
|
| [] -> raise Not_found in
|
|
|
|
|
|
let children = Xml.children xml in
|
|
|
|
(* Let's try with a numeric index *)
|
|
try (Array.of_list children).(int_of_string c) with
|
|
Failure "int_of_string" -> (* Bad luck. Go through the children *)
|
|
find children
|
|
|
|
|
|
let get xml path =
|
|
let p = Str.split sep path in
|
|
let rec iter xml = function
|
|
[] -> failwith "ExtXml.get: empty path"
|
|
| [x] -> ( try if Xml.tag xml <> x then raise Not_found else xml with _ -> raise Not_found )
|
|
| x::xs -> iter (child xml x) xs in
|
|
iter xml p
|
|
|
|
let get_attrib xml path attr =
|
|
Xml.attrib (get xml path) attr
|
|
|
|
let sprint_fields = fun () l ->
|
|
"<"^
|
|
List.fold_right (fun (a, b) -> (^) (Printf.sprintf "%s=\"%s\" " a b)) l ">"
|
|
|
|
let attrib = fun x a ->
|
|
try
|
|
Xml.attrib x a
|
|
with
|
|
Xml.No_attribute _ ->
|
|
raise (Error (Printf.sprintf "Error: Attribute '%s' expected in <%a>" a sprint_fields (Xml.attribs x)))
|
|
|
|
let tag_is = fun x v ->
|
|
String.lowercase (Xml.tag x) = String.lowercase v
|
|
|
|
|
|
|
|
let attrib_or_default = fun x a default ->
|
|
try Xml.attrib x a with _ -> default
|
|
|
|
|
|
(** Code patched from xml.ml from xml-light package: PC Data formatting removed *)
|
|
let tmp = Buffer.create 200
|
|
let buffer_attr = fun indent tab (n,v) ->
|
|
if indent then
|
|
Buffer.add_string tmp tab;
|
|
Buffer.add_char tmp ' ';
|
|
Buffer.add_string tmp n;
|
|
Buffer.add_string tmp "=\"";
|
|
let l = String.length v in
|
|
for p = 0 to l-1 do
|
|
match v.[p] with
|
|
| '\\' -> Buffer.add_string tmp "\\\\"
|
|
| '"' -> Buffer.add_string tmp "\\\""
|
|
| c -> Buffer.add_char tmp c
|
|
done;
|
|
Buffer.add_char tmp '"';
|
|
if indent then
|
|
Buffer.add_char tmp '\n'
|
|
|
|
let buffer_pcdata = Buffer.add_string tmp
|
|
let my_to_string_fmt = fun tab_attribs x ->
|
|
let rec loop ?(newl=false) tab = function
|
|
| Xml.Element (tag,alist,[]) ->
|
|
Buffer.add_string tmp tab;
|
|
Buffer.add_char tmp '<';
|
|
Buffer.add_string tmp tag;
|
|
if tab_attribs then Buffer.add_char tmp '\n';
|
|
List.iter (buffer_attr tab_attribs tab) alist;
|
|
if tab_attribs then Buffer.add_string tmp tab;
|
|
Buffer.add_string tmp "/>";
|
|
if newl then Buffer.add_char tmp '\n';
|
|
| Xml.Element (tag,alist,[Xml.PCData text]) ->
|
|
Buffer.add_string tmp tab;
|
|
Buffer.add_char tmp '<';
|
|
Buffer.add_string tmp tag;
|
|
List.iter (buffer_attr tab_attribs tab) alist;
|
|
Buffer.add_string tmp ">";
|
|
buffer_pcdata text;
|
|
Buffer.add_string tmp "</";
|
|
Buffer.add_string tmp tag;
|
|
Buffer.add_char tmp '>';
|
|
if newl then Buffer.add_char tmp '\n';
|
|
| Xml.Element (tag,alist,l) ->
|
|
Buffer.add_string tmp tab;
|
|
Buffer.add_char tmp '<';
|
|
Buffer.add_string tmp tag;
|
|
List.iter (buffer_attr tab_attribs tab) alist;
|
|
Buffer.add_string tmp ">\n";
|
|
List.iter (loop ~newl:true (tab^" ")) l;
|
|
Buffer.add_string tmp tab;
|
|
Buffer.add_string tmp "</";
|
|
Buffer.add_string tmp tag;
|
|
Buffer.add_char tmp '>';
|
|
if newl then Buffer.add_char tmp '\n';
|
|
| Xml.PCData text ->
|
|
buffer_pcdata text;
|
|
if newl then Buffer.add_char tmp '\n';
|
|
in
|
|
Buffer.reset tmp;
|
|
loop "" x;
|
|
let s = Buffer.contents tmp in
|
|
Buffer.reset tmp;
|
|
s
|
|
|
|
|
|
|
|
let to_string_fmt = fun ?(tab_attribs = false) xml ->
|
|
let l = String.lowercase in
|
|
let rec lower = function
|
|
Xml.PCData _ as x -> x
|
|
| Xml.Element (t, ats, cs) ->
|
|
Xml.Element(l t,
|
|
List.map (fun (a,v) -> (l a, v)) ats,
|
|
List.map lower cs) in
|
|
my_to_string_fmt tab_attribs (lower xml)
|
|
|
|
|
|
let subst_attrib = fun attrib value xml ->
|
|
let u = String.uppercase in
|
|
let uattrib = u attrib in
|
|
match xml with
|
|
Xml.Element (tag, attrs, children) ->
|
|
let rec loop = function
|
|
[] -> [(attrib, value)]
|
|
| (a,_v) as c::ats ->
|
|
if u a = uattrib then loop ats else c::loop ats in
|
|
Xml.Element (tag,
|
|
loop attrs,
|
|
children)
|
|
| Xml.PCData _ -> xml
|
|
|
|
|
|
let subst_child = fun ?(select= fun _ -> true) t x xml ->
|
|
match xml with
|
|
Xml.Element (tag, attrs, children) ->
|
|
let found = ref false in
|
|
let new_children =
|
|
List.map
|
|
(fun xml -> if tag_is xml t && select xml then (found := true; x) else xml)
|
|
children in
|
|
if !found then
|
|
Xml.Element (tag, attrs, new_children)
|
|
else
|
|
raise Not_found
|
|
| Xml.PCData _ -> xml
|
|
|
|
|
|
let subst_or_add_child = fun t x xml ->
|
|
try subst_child t x xml with Not_found ->
|
|
match xml with
|
|
Xml.Element (tag, attrs, children) ->
|
|
Xml.Element (tag, attrs, x::children)
|
|
| Xml.PCData _ -> xml
|
|
|
|
|
|
let remove_child = fun ?(select= fun _ -> true) t xml ->
|
|
match xml with
|
|
Xml.Element (tag, attrs, children) ->
|
|
Xml.Element (tag,
|
|
attrs,
|
|
List.fold_right (fun xml rest -> if tag_is xml t && select xml then rest else xml::rest) children [])
|
|
| Xml.PCData _ -> xml
|
|
|
|
|
|
let float_attrib = fun xml a ->
|
|
let v = attrib xml a in
|
|
try
|
|
float_of_string v
|
|
with
|
|
_ -> failwith (Printf.sprintf "Error: float expected in '%s'" v)
|
|
|
|
let int_attrib = fun xml a ->
|
|
let v = attrib xml a in
|
|
try
|
|
int_of_string v
|
|
with
|
|
_ -> failwith (Printf.sprintf "Error: integer expected in '%s'" v)
|
|
|
|
|
|
(* When an .xml is coming through http, the dtd is not available. We disable
|
|
the DTD proving feature in this case. FIXME: We should use the resolve
|
|
feature *)
|
|
let my_xml_parse_file =
|
|
let parser = XmlParser.make () in
|
|
XmlParser.prove parser false;
|
|
fun f ->
|
|
XmlParser.parse parser (XmlParser.SFile f)
|
|
|
|
|
|
let parse_file = fun ?(noprovedtd = false) file ->
|
|
try
|
|
(if noprovedtd then my_xml_parse_file else Xml.parse_file) file
|
|
with
|
|
Xml.Error e -> failwith (sprintf "%s: %s" file (Xml.error e))
|
|
| Xml.File_not_found f -> failwith (sprintf "File not found: %s" f)
|
|
| Dtd.Prove_error e -> failwith (sprintf "%s: %s" file (Dtd.prove_error e))
|
|
| Dtd.Check_error e -> failwith (sprintf "%s: %s" file (Dtd.check_error e))
|
|
| Dtd.Parse_error e -> failwith (sprintf "%s: %s" file (Dtd.parse_error e))
|
|
|
|
|
|
|
|
let digest = fun xml ->
|
|
Digest.string (Xml.to_string xml)
|
|
|
|
let predefined_general_entities =
|
|
[ Str.regexp "&", "&";
|
|
Str.regexp """, "\"" ]
|
|
|
|
let display_entities = fun s ->
|
|
List.fold_right
|
|
(fun (regexp, displayed_as) r -> Str.global_replace regexp displayed_as r)
|
|
predefined_general_entities
|
|
s
|
|
|
|
module Gconf = struct
|
|
let get_value = fun xml name ->
|
|
let e = child ~select:(fun x -> Xml.attrib x "name" = name) xml "entry" in
|
|
Xml.attrib e "value"
|
|
|
|
let entry = fun application name value ->
|
|
Xml.Element ("entry", ["name", name;
|
|
"value", value;
|
|
"application", application],
|
|
[])
|
|
|
|
let add_entry = fun xml appli name value ->
|
|
let entry = entry appli name value in
|
|
let select = fun x -> Xml.attrib x "name" = name in
|
|
let xml = remove_child ~select "entry" xml in
|
|
Xml.Element (Xml.tag xml, Xml.attribs xml, entry::Xml.children xml)
|
|
end
|