/[svn]/schema/schema_builtin.ml
ViewVC logotype

Contents of /schema/schema_builtin.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 656 - (hide annotations)
Tue Jul 10 17:51:50 2007 UTC (5 years, 10 months ago) by abate
File size: 13194 byte(s)
[r2003-09-16 21:30:42 by cvscast] Cleaning in progress... + no more uppercase/lowercase distinction for
identifiers

Original author: cvscast
Date: 2003-09-16 21:30:45+00:00
1 abate 500
2 abate 507 open Printf
3     open Schema_types
4 abate 500
5     (* TODO dates: boundary checks (e.g. 95/26/2003) *)
6     (* TODO a lot of almost cut-and-paste code, expecially in gFoo types validation
7     *)
8    
9     (* auxiliary stuff *)
10    
11     let char_of_hex =
12     let int_of_hex_char = function
13     | '0' -> 0 | '1' -> 1 | '2' -> 2 | '3' -> 3 | '4' -> 4 | '5' -> 5 | '6' -> 6
14     | '7' -> 7 | '8' -> 8 | '9' -> 9 | 'a' | 'A' -> 10 | 'b' | 'B' -> 11
15     | 'c' | 'C' -> 12 | 'd' | 'D' -> 13 | 'e' | 'E' -> 14 | 'f' | 'F' -> 15
16     | _ -> assert false
17     in
18     (* most significative, least significative *)
19     fun ms ls -> Char.unsafe_chr (int_of_hex_char ms * 16 + int_of_hex_char ls)
20    
21 abate 507 let strip_parens s = Pcre.replace ~pat:"[()]" s
22     let add_limits s = "^" ^ s ^ "$"
23 abate 500
24     let simple_type_error ~typ ~value =
25     raise (XSI_validation_error (sprintf "'%s' isn't a valid xsd:%s" value typ))
26    
27     (* regular expressions used to validate built-in types *)
28    
29 abate 507 let timezone_RE_raw = "(Z)|(([+-])?(\\d{2}):(\\d{2}))"
30     let date_RE_raw = "(\\d{4,})-(\\d{2})-(\\d{2})"
31     let time_RE_raw = "(\\d{2}):(\\d{2}):(\\d{2})"
32 abate 500
33 abate 507 let gYearMonth_RE_raw = sprintf "(-)?(\\d{4,})-(\\d{2})(%s)?" timezone_RE_raw
34     let gYear_RE_raw = sprintf "(-)?(\\d{4,})(%s)?" timezone_RE_raw
35     let gMonthDay_RE_raw = sprintf "--(\\d{2})-(\\d{2})(%s)?" timezone_RE_raw
36     let gDay_RE_raw = sprintf "---(\\d{2})(%s)?" timezone_RE_raw
37     let gMonth_RE_raw = "--(\\d{2})--(%s)?"
38 abate 500
39 abate 507 let positive_field = false, "positive", Builtin_defs.bool
40     let year_field = false, "year", Builtin_defs.int
41     let month_field = false, "month", Builtin_defs.int
42     let day_field = false, "day", Builtin_defs.int
43     let hour_field = false, "hour", Builtin_defs.int
44     let minute_field = false, "minute", Builtin_defs.int
45 abate 500 let second_field = false, "second", Builtin_defs.int ;; (* TODO this should be a decimal *)
46    
47     (* some cduce types corresponding to schema ones *)
48    
49     (* TODO the constraint that at least one part should be present isn't easily
50     expressible with CDuce types *)
51     let duration_type = Types.rec_of_list' [
52     positive_field;
53     true, "year", Builtin_defs.int;
54     true, "month", Builtin_defs.int;
55     true, "day", Builtin_defs.int;
56     true, "hour", Builtin_defs.int;
57     true, "minute", Builtin_defs.int;
58     true, "second", Builtin_defs.int; (* TODO this should be a decimal *)
59 abate 507 ]
60 abate 500
61     let timezone_type = Types.rec_of_list' [
62     false, "positive", Builtin_defs.bool;
63     hour_field; minute_field
64 abate 507 ]
65 abate 500
66 abate 507 let timezone_type_fields = [ true, "timezone", timezone_type ]
67     let time_type_fields = [ hour_field; minute_field; second_field ]
68     let date_type_fields = [ year_field; month_field; day_field ]
69 abate 500
70 abate 507 let time_type = Types.rec_of_list' (time_type_fields @ timezone_type_fields)
71     let date_type = Types.rec_of_list' (positive_field :: date_type_fields)
72 abate 500 let dateTime_type =
73     Types.rec_of_list' (positive_field ::
74     (date_type_fields @ time_type_fields @ timezone_type_fields))
75     let gYearMonth_type = Types.rec_of_list' [
76     positive_field; year_field; month_field
77 abate 507 ]
78     let gYear_type = Types.rec_of_list' [ positive_field; year_field ]
79     let gMonthDay_type = Types.rec_of_list' [ month_field; day_field ]
80     let gDay_type = Types.rec_of_list' [ day_field ]
81     let gMonth_type = Types.rec_of_list' [ month_field ]
82 abate 500
83 abate 507 let nonPositiveInteger_type = Builtin_defs.non_pos_int
84     let negativeInteger_type = Builtin_defs.neg_int
85     let nonNegativeInteger_type = Builtin_defs.non_neg_int
86     let positiveInteger_type = Builtin_defs.pos_int
87 abate 500
88     (* validation functions: string -> Value.t *)
89    
90 abate 507 let validate_string = Value.string_latin1
91 abate 500
92     let validate_integer s =
93     try
94 abate 656 Value.Integer (Intervals.V.mk s)
95 abate 500 with Failure _ -> simple_type_error ~typ:"integer" ~value:s
96     let validate_interval interval type_name s =
97     let integer =
98     try
99 abate 656 Intervals.V.mk s
100 abate 500 with Failure _ -> simple_type_error ~typ:type_name ~value:s
101     in
102     if Intervals.contains integer interval then
103     Value.Integer integer
104     else
105     simple_type_error ~typ:type_name ~value:s
106     let validate_nonPositiveInteger =
107 abate 656 validate_interval (Intervals.left Intervals.V.zero) "nonPositiveInteger"
108 abate 500 let validate_negativeInteger =
109 abate 656 validate_interval (Intervals.left Intervals.V.minus_one) "negativeInteger"
110 abate 500 let validate_nonNegativeInteger =
111 abate 656 validate_interval (Intervals.right Intervals.V.zero) "nonNegativeInteger"
112 abate 500 let validate_positiveInteger =
113 abate 656 validate_interval (Intervals.right Intervals.V.one) "positiveInteger"
114 abate 500
115     let validate_bool = function
116     | "true" | "1" -> Value.vtrue
117     | "false" | "0" -> Value.vfalse
118     | v -> simple_type_error ~typ:"boolean" ~value:v
119    
120 abate 507 let parse_sign = function "+" | "" -> Value.vtrue | _ -> Value.vfalse
121 abate 500
122     let parse_date =
123     let rex = Pcre.regexp (add_limits date_RE_raw) in
124     fun s ->
125     let abort () = simple_type_error ~typ:"date" ~value:s in
126     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
127     [ "year", validate_integer subs.(1);
128     "month", validate_integer subs.(2);
129     "day", validate_integer subs.(3) ]
130    
131     let parse_time =
132     let rex = Pcre.regexp (add_limits time_RE_raw) in
133     fun s ->
134     let abort () = simple_type_error ~typ:"time" ~value:s in
135     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
136     [ "hour", validate_integer subs.(1);
137     "minute", validate_integer subs.(2);
138     "second", validate_integer subs.(3) ]
139    
140     let parse_timezone =
141     let rex = Pcre.regexp (add_limits timezone_RE_raw) in
142     fun s ->
143     let abort () =
144     raise (XSI_validation_error (sprintf "'%s' isn't a valid timezone" s))
145     in
146     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
147     match subs.(1) with
148     | "Z" ->
149     ["positive", Value.vtrue;
150     "hour", validate_integer "0";
151     "minute", validate_integer "0"]
152     | _ ->
153     ["positive", parse_sign subs.(3);
154     "hour", validate_integer subs.(4);
155     "minute", validate_integer subs.(5)]
156     (* parse a timezone from a string, if it's empty return the empty list,
157     otherwise return a list containing a pair <"timezone", timezone value> *)
158     let parse_timezone' = function
159     | "" -> []
160     | v -> [ "timezone", Value.vrecord (parse_timezone v) ]
161    
162     let validate_duration =
163     let rex = Pcre.regexp
164     "^([+-])?P((\\d+)Y)?((\\d+)M)?((\\d+)D)?(T((\\d+)H)?((\\d+)M)?((\\d+)S)?)?$"
165     in
166     fun s ->
167     let abort () = simple_type_error ~typ:"duration" ~value:s in
168     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
169     try
170     let fields =
171     ["positive", parse_sign subs.(1) ] @
172     (match subs.(3) with "" -> [] | v -> ["year", validate_integer v]) @
173     (match subs.(5) with "" -> [] | v -> ["month", validate_integer v]) @
174     (match subs.(7) with "" -> [] | v -> ["day", validate_integer v]) @
175     (match subs.(10) with "" -> [] | v -> ["hour", validate_integer v]) @
176     (match subs.(12) with "" -> [] | v -> ["minute", validate_integer v]) @
177     (match subs.(14) with "" -> [] | v -> ["second", validate_integer v])
178     in
179     Value.vrecord fields
180     with XSI_validation_error _ -> abort ()
181    
182     let validate_dateTime =
183     let rex = Pcre.regexp (sprintf "^([+-])?(%s)T(%s)(%s)?$"
184     (strip_parens date_RE_raw) (strip_parens time_RE_raw)
185     (strip_parens timezone_RE_raw))
186     in
187     fun s ->
188     let abort () = simple_type_error ~typ:"dateTime" ~value:s in
189     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
190     try
191     let fields =
192     [ "positive", parse_sign subs.(1) ] @
193     parse_date subs.(2) @
194     parse_time subs.(3) @
195     parse_timezone' subs.(4)
196     in
197     Value.vrecord fields
198     with XSI_validation_error _ -> abort ()
199    
200     let validate_gYearMonth =
201     let rex = Pcre.regexp (add_limits gYearMonth_RE_raw) in
202     fun s ->
203     let abort () = simple_type_error ~typ:"gYearMonth" ~value:s in
204     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
205     try
206     let fields = [
207     "positive", parse_sign subs.(1);
208     "year", validate_integer subs.(2);
209     "month", validate_integer subs.(3)
210     ] @ parse_timezone' subs.(4)
211     in
212     Value.vrecord fields
213     with XSI_validation_error _ -> abort ()
214    
215     let validate_gYear =
216     let rex = Pcre.regexp (add_limits gYear_RE_raw) in
217     fun s ->
218     let abort () = simple_type_error ~typ:"gYear" ~value:s in
219     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
220     try
221     let fields = [
222     "positive", parse_sign subs.(1);
223     "year", validate_integer subs.(2);
224     ] @ parse_timezone' subs.(3)
225     in
226     Value.vrecord fields
227     with XSI_validation_error _ -> abort ()
228    
229     let validate_gMonthDay =
230     let rex = Pcre.regexp (add_limits gMonthDay_RE_raw) in
231     fun s ->
232     let abort () = simple_type_error ~typ:"gMonthDay" ~value:s in
233     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
234     try
235     let fields = [
236     "month", validate_integer subs.(1);
237     "day", validate_integer subs.(2);
238     ] @ parse_timezone' subs.(3)
239     in
240     Value.vrecord fields
241     with XSI_validation_error _ -> abort ()
242    
243     let validate_gDay =
244     let rex = Pcre.regexp (add_limits gDay_RE_raw) in
245     fun s ->
246     let abort () = simple_type_error ~typ:"gDay" ~value:s in
247     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
248     try
249     let fields =
250     ("day", validate_integer subs.(1)) :: (parse_timezone' subs.(2))
251     in
252     Value.vrecord fields
253     with XSI_validation_error _ -> abort ()
254    
255     let validate_gMonth =
256     let rex = Pcre.regexp (add_limits gMonth_RE_raw) in
257     fun s ->
258     let abort () = simple_type_error ~typ:"gMonth" ~value:s in
259     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
260     try
261     let fields =
262     ("month", validate_integer subs.(1)) :: (parse_timezone' subs.(2))
263     in
264     Value.vrecord fields
265     with XSI_validation_error _ -> abort ()
266    
267     let validate_time =
268     let rex = Pcre.regexp (sprintf "^(%s)(%s)?$" (strip_parens time_RE_raw)
269     (strip_parens timezone_RE_raw))
270     in
271     fun s ->
272     let abort () = simple_type_error ~typ:"time" ~value:s in
273     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
274     try
275     let fields =
276     parse_time subs.(1) @
277     (match subs.(2) with
278     | "" -> []
279     | v -> [ "timezone", Value.vrecord (parse_timezone v) ])
280     in
281     Value.vrecord fields
282     with XSI_validation_error _ -> abort ()
283    
284     let validate_date =
285     let rex = Pcre.regexp (sprintf "^(-)?(%s)(%s)?$" (strip_parens date_RE_raw)
286     (strip_parens timezone_RE_raw))
287     in
288     fun s ->
289     let abort () = simple_type_error ~typ:"date" ~value:s in
290     let subs = try Pcre.extract ~rex s with Not_found -> abort () in
291     try
292     let fields =
293     [ "positive", parse_sign subs.(1) ] @
294     parse_date subs.(2) @
295     (match subs.(3) with
296     | "" -> []
297     | v -> [ "timezone", Value.vrecord (parse_timezone v) ])
298     in
299     Value.vrecord fields
300     with XSI_validation_error _ -> abort ()
301    
302     let validate_hexBinary s =
303     let len = String.length s in
304     if len mod 2 <> 0 then
305     simple_type_error ~typ:"hexBinary" ~value:s;
306     let res = String.create (len / 2) in
307     let rec aux idx =
308     if idx < len then begin
309     String.unsafe_set res (idx / 2)
310     (char_of_hex (String.unsafe_get s idx) (String.unsafe_get s (idx + 1)));
311     aux (idx + 2)
312     end
313     in
314     aux 0;
315     validate_string res
316    
317     (* TODO test base64Binary simple type! *)
318 abate 507 let validate_base64Binary s = validate_string (Netencoding.Base64.decode s)
319 abate 500
320     let validate_anyURI s =
321     try
322     validate_string (Neturl.string_of_url (Neturl.url_of_string
323     Neturl.ip_url_syntax s))
324     with Neturl.Malformed_URL -> simple_type_error ~typ:"anyURI" ~value:s
325    
326     let builtins = [
327     "xsd:string", (Builtin_defs.string, validate_string);
328     "xsd:integer", (Builtin_defs.int, validate_integer);
329     "xsd:nonPositiveInteger",
330     (nonPositiveInteger_type, validate_nonPositiveInteger);
331     "xsd:negativeInteger", (negativeInteger_type, validate_negativeInteger);
332     "xsd:nonNegativeInteger",
333     (nonNegativeInteger_type, validate_nonNegativeInteger);
334     "xsd:positiveInteger", (positiveInteger_type, validate_positiveInteger);
335     "xsd:boolean", (Builtin_defs.bool, validate_bool);
336     "xsd:hexBinary", (Builtin_defs.string, validate_hexBinary);
337     "xsd:base64Binary", (Builtin_defs.string, validate_base64Binary);
338     "xsd:anyURI", (Builtin_defs.string, validate_anyURI);
339     (* TODO anyType: is this useful? *)
340     "xsd:anyType", (Types.any, (fun _ -> assert false));
341     (* TODO anySimpleType: is ok as a string? *)
342     "xsd:anySimpleType", (Builtin_defs.string, validate_string);
343     "xsd:duration", (duration_type, validate_duration);
344     "xsd:dateTime", (dateTime_type, validate_dateTime);
345     "xsd:time", (time_type, validate_time);
346     "xsd:date", (date_type, validate_date);
347     "xsd:gYearMonth", (gYearMonth_type, validate_gYearMonth);
348     "xsd:gYear", (gYear_type, validate_gYear);
349     "xsd:gMonthDay", (gMonthDay_type, validate_gMonthDay);
350     "xsd:gDay", (gDay_type, validate_gDay);
351     "xsd:gMonth", (gMonth_type, validate_gMonth);
352 abate 507 ]
353 abate 500
354     (* module's interface implementation *)
355    
356 abate 507 let names = List.sort compare (List.map fst builtins)
357     let len = List.length builtins
358     let cd_types = Hashtbl.create len
359     let validators = Hashtbl.create len
360     let __validate_fun_of_builtin = Hashtbl.find validators
361     let cd_type_of_builtin = Hashtbl.find cd_types
362 abate 500
363     let fill () =
364     List.iter
365     (fun (name, (typ, validator)) ->
366     Hashtbl.add cd_types name typ;
367     Hashtbl.add validators name validator)
368     builtins
369    
370 abate 507 let _ = fill ()
371 abate 500

CVS Admin">CVS Admin
ViewVC Help
Powered by ViewVC 1.1.5