Source file xml_light.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
open StdLabels
open Protocol_conv.Runtime
type t = Xml.xml
type 'a flags = 'a no_flags
let _log fmt = Printf.eprintf (fmt ^^ "\n%!")
module StringMap = Map.Make(String)
exception Protocol_error of string * t
let () = Printexc.register_printer
(function Protocol_error (s, t) -> Some (s ^ ": " ^ (Xml.to_string t))
| _ -> None)
let raise_errorf t fmt =
Printf.kprintf (fun s -> raise (Protocol_error (s, t))) fmt
let rec element_to_map m = function
| (Xml.Element(name, _, _) as x) :: xs ->
let m =
let ks = try StringMap.find name m with Not_found -> [] in
StringMap.add name (x :: ks) m
in
element_to_map m xs
| _ :: xs -> element_to_map m xs
| [] -> m
let element name t = Xml.Element (name, [], t)
let of_variant: (('a -> string * t list) -> 'a -> t) flags = fun destruct t ->
let (s, ts) = destruct t in
Xml.Element("variant", [], Xml.PCData s :: ts)
let to_variant: ((string * t list -> 'a) -> t -> 'a) flags = fun constr -> function
| Xml.Element(_, _, Xml.PCData s :: es) -> constr (s, es)
| Xml.Element(name, _, []) as d -> raise_errorf d "No contents for variant type: %s" name
| d -> raise_errorf d "Wrong variant data"
let to_record: type a b. (t, a, b) structure -> a -> t -> b = fun spec ->
let rec inner: type a b. (t, a, b) structure -> a -> 't -> b = function
| Cons ((field, to_value_func), xs) ->
let cont = inner xs in
fun constr t ->
let values = try StringMap.find field t |> List.rev with Not_found -> [] in
let arg = match values with
| [ Xml.Element (name, _, xs) ] -> Xml.Element (name, ["record", "unwrapped"], xs)
| [ Xml.PCData _ as d ] -> d
| xs -> Xml.Element (field, [], xs)
in
let v = to_value_func arg
in
cont (constr v) t
| Nil -> fun a _t -> a
in
let f = inner spec in
fun constr -> function
| Xml.Element (_, _, t) ->
let m = StringMap.empty in
f constr (element_to_map m t)
| e -> raise_errorf e "Not a record superstruture"
let of_record: (string * t) list -> t = fun assoc ->
List.map ~f:(
function
| (field, Xml.Element ("record", attrs, xs)) -> [Xml.Element (field, attrs, xs)]
| (field, Xml.Element ("variant", attrs, xs)) -> [Xml.Element (field, attrs, xs)]
| (field, Xml.Element ("__option", attrs, xs)) -> [Xml.Element (field, attrs, xs)]
| (field, Xml.Element (_, _, xs)) ->
List.map ~f:(function
| Xml.Element(_, attrs, xs) ->
Xml.Element(field, attrs, xs)
| PCData _ as p -> Xml.Element(field, [], [p])
) xs
| (field, e) -> raise_errorf e "Must be an element: %s" field
) assoc |> List.flatten |> element "record"
let to_tuple = to_record
let of_tuple = of_record
let to_option: (t -> 'a) -> t -> 'a option = fun to_value_fun t ->
match t with
| Xml.Element (_, [_, "unwrapped"], [])
| Xml.Element (_, _, [])
| Xml.Element (_, _, [ PCData ""] ) ->
None
| Xml.Element (_, [_, "unwrapped"], [ (Element ("__option", _, _) as t)])
| Xml.Element ("__option", _, [t])
| t ->
Some (to_value_fun t)
let of_option: ('a -> t) -> 'a option -> t = fun of_value_fun v ->
let t = match v with
| None ->
Xml.Element ("__option", [], [])
| Some x -> begin
match of_value_fun x with
| (Xml.Element ("__option", _, _) as t) ->
Xml.Element ("__option", [], [t])
| t ->
t
end
in
t
(** If the given list has been unwrapped since its part of a record, we "rewrap it". *)
let to_list: (t -> 'a) -> t -> 'a list = fun to_value_fun -> function
| Xml.Element (_, [_, "unwrapped"], _) as elm ->
[ to_value_fun elm ]
| Xml.Element (_, _, ts) ->
List.map ~f:(fun t -> to_value_fun t) ts
| e -> raise_errorf e "Must be an element type"
let of_list: ('a -> t) -> 'a list -> t = fun of_value_fun vs ->
Xml.Element("l", [], List.map ~f:(fun v -> of_value_fun v) vs)
let to_array: (t -> 'a) -> t -> 'a array = fun to_value_fun t ->
to_list to_value_fun t |> Array.of_list
let of_array: ('a -> t) -> 'a array -> t = fun of_value_fun vs ->
of_list of_value_fun (Array.to_list vs)
let to_lazy_t: (t -> 'a) -> t -> 'a lazy_t = fun to_value_fun t -> Lazy.from_fun (fun () -> to_value_fun t)
let of_lazy_t: ('a -> t) -> 'a lazy_t -> t = fun of_value_fun v ->
Lazy.force v |> of_value_fun
let of_value to_string v = Xml.Element ("p", [], [ Xml.PCData (to_string v) ])
let to_value type_name of_string = function
| Xml.Element(_, _, []) -> of_string ""
| Xml.Element(_, _, [PCData s]) -> of_string s
| Xml.Element(name, _, _) as e -> raise_errorf e "Primitive value expected in node: %s for %s" name type_name
| Xml.PCData _ as e -> raise_errorf e "Primitive type not expected here when deserializing %s" type_name
let to_bool = to_value "bool" bool_of_string
let of_bool = of_value string_of_bool
let to_int = to_value "int" int_of_string
let of_int = of_value string_of_int
let to_int32 = to_value "int32" Int32.of_string
let of_int32 = of_value Int32.to_string
let to_int64 = to_value "int64" Int64.of_string
let of_int64 = of_value Int64.to_string
let to_float = to_value "float" float_of_string
let of_float = of_value string_of_float
let to_string = to_value "string" (fun x -> x)
let of_string = of_value (fun x -> x)
let to_unit = to_value "unit" (function "()" -> () | _ -> failwith "expected unit")
let of_unit = of_value (fun () -> "()")
let of_xml_light t = t
let to_xml_light t = t