···137137 ensure s len;
138138 let avail = s.buf_len - s.buf_pos in
139139 if avail < len then
140140- Error (Printf.sprintf "unexpected end of input, expected %S" str)
140140+ Error (Fmt.str "unexpected end of input, expected %S" str)
141141 else
142142 let rec check i =
143143 if i >= len then begin
···146146 Ok ()
147147 end
148148 else if Stdlib.Bytes.get s.buf (s.buf_pos + i) <> str.[i] then
149149- Error (Printf.sprintf "expected %S at position %d" str s.total_pos)
149149+ Error (Fmt.str "expected %S at position %d" str s.total_pos)
150150 else check (i + 1)
151151 in
152152 check 0
···159159160160 let parse_name s =
161161 match peek s with
162162- | None ->
163163- Error
164164- (Printf.sprintf "expected element name at position %d" s.total_pos)
162162+ | None -> Error (Fmt.str "expected element name at position %d" s.total_pos)
165163 | Some c when not (is_name_start_char c) ->
166166- Error
167167- (Printf.sprintf "expected element name at position %d" s.total_pos)
164164+ Error (Fmt.str "expected element name at position %d" s.total_pos)
168165 | _ ->
169166 let nbuf = Buffer.create 16 in
170167 let rec loop () =
···186183 | "gt" -> Ok '>'
187184 | "quot" -> Ok '"'
188185 | "apos" -> Ok '\''
189189- | name -> Error (Printf.sprintf "unknown entity reference: &%s;" name)
186186+ | name -> Error (Fmt.str "unknown entity reference: &%s;" name)
190187191188 let decode_char_ref s =
192189 let n =
···194191 else int_of_string_opt s
195192 in
196193 match n with
197197- | None -> Error (Printf.sprintf "invalid character reference: &#%s;" s)
194194+ | None -> Error (Fmt.str "invalid character reference: &#%s;" s)
198195 | Some code ->
199196 if code < 0 || code > 0x10FFFF then
200200- Error (Printf.sprintf "character reference out of range: &#%s;" s)
197197+ Error (Fmt.str "character reference out of range: &#%s;" s)
201198 else
202199 let buf = Buffer.create 4 in
203200 if code < 0x80 then Buffer.add_char buf (Char.chr code)
···260257 let quote = consume s in
261258 if quote <> '"' && quote <> '\'' then
262259 Error
263263- (Printf.sprintf "expected quote character at position %d"
264264- (s.total_pos - 1))
260260+ (Fmt.str "expected quote character at position %d" (s.total_pos - 1))
265261 else
266262 let buf = Buffer.create 32 in
267263 let rec loop () =
···452448 | Ok close_tag ->
453449 if close_tag <> tag then
454450 Error
455455- (Printf.sprintf "mismatched tags: opened <%s> but closed </%s>"
456456- tag close_tag)
451451+ (Fmt.str "mismatched tags: opened <%s> but closed </%s>" tag
452452+ close_tag)
457453 else begin
458454 skip_ws s;
459455 expect_string s ">"
···660656 mutable in_start_tag : bool;
661657}
662658663663-let make_encoder ?(indent = 0) w =
664664- { w; indent; depth = 0; in_start_tag = false }
659659+let encoder ?(indent = 0) w = { w; indent; depth = 0; in_start_tag = false }
665660666661let enc_start_tag (e : encoder) tag =
667662 if e.indent > 0 && e.depth > 0 then begin
···920915 (fun s ->
921916 match int_of_string_opt s with
922917 | Some n -> Ok n
923923- | None ->
924924- Error (Printf.sprintf "expected integer attribute, got %S" s));
918918+ | None -> Error (Fmt.str "expected integer attribute, got %S" s));
925919 enc = string_of_int;
926920 }
927921···931925 (fun s ->
932926 match float_of_string_opt s with
933927 | Some f -> Ok f
934934- | None -> Error (Printf.sprintf "expected float attribute, got %S" s));
928928+ | None -> Error (Fmt.str "expected float attribute, got %S" s));
935929 enc = string_of_float;
936930 }
937931···942936 match String.lowercase_ascii s with
943937 | "true" -> Ok true
944938 | "false" -> Ok false
945945- | _ -> Error (Printf.sprintf "expected boolean attribute, got %S" s));
939939+ | _ -> Error (Fmt.str "expected boolean attribute, got %S" s));
946940 enc = string_of_bool;
947941 }
948942···10371031 m.base_dec s
10381032 | Element (tag, inner) ->
10391033 if el.Tree.tag <> tag then
10401040- Error (Printf.sprintf "expected element <%s>, got <%s>" tag el.Tree.tag)
10341034+ Error (Fmt.str "expected element <%s>, got <%s>" tag el.Tree.tag)
10411035 else dec_tree inner el
10421036 | El (tag, map) ->
10431037 if tag <> "" && el.Tree.tag <> tag then
10441044- Error (Printf.sprintf "expected element <%s>, got <%s>" tag el.Tree.tag)
10381038+ Error (Fmt.str "expected element <%s>, got <%s>" tag el.Tree.tag)
10451039 else dec_tree_el map el
10461040 | Raw -> Ok el
10471041 | Map mw -> (
···11071101 match field with
11081102 | Attr (name, codec, id, _enc) -> (
11091103 match List.assoc_opt name attrs with
11101110- | None ->
11111111- Error (Printf.sprintf "missing required attribute %S on element" name)
11041104+ | None -> Error (Fmt.str "missing required attribute %S on element" name)
11121105 | Some s -> (
11131106 match codec.dec s with
11141107 | Ok v -> Ok (Dict.add id v dict)
···11301123 loop children
11311124 in
11321125 match child_el with
11331133- | None -> Error (Printf.sprintf "missing required child element <%s>" tag)
11261126+ | None -> Error (Fmt.str "missing required child element <%s>" tag)
11341127 | Some el -> (
11351128 match dec_tree inner el with
11361129 | Ok v -> Ok (Dict.add id v dict)
···11821175 | Ok text -> m.base_dec (String.trim text))
11831176 | Element (el_tag, inner) -> (
11841177 if tag <> el_tag then
11851185- Error (Printf.sprintf "expected element <%s>, got <%s>" el_tag tag)
11781178+ Error (Fmt.str "expected element <%s>, got <%s>" el_tag tag)
11861179 else
11871180 let result = dec_stream inner s ~tag ~attrs ~self_close in
11881181 if self_close then result
···11951188 | Ok () -> Ok v))
11961189 | El (el_tag, map) -> (
11971190 if el_tag <> "" && tag <> el_tag then
11981198- Error (Printf.sprintf "expected element <%s>, got <%s>" el_tag tag)
11911191+ Error (Fmt.str "expected element <%s>, got <%s>" el_tag tag)
11991192 else
12001193 let result = dec_stream_el map s ~attrs ~self_close in
12011194 if self_close then result
···13561349 (fun s ->
13571350 match int_of_string_opt s with
13581351 | Some n -> Ok n
13591359- | None -> Error (Printf.sprintf "expected integer, got %S" s));
13521352+ | None -> Error (Fmt.str "expected integer, got %S" s));
13601353 base_enc = string_of_int;
13611354 }
13621355···13681361 (fun s ->
13691362 match float_of_string_opt s with
13701363 | Some f -> Ok f
13711371- | None -> Error (Printf.sprintf "expected float, got %S" s));
13641364+ | None -> Error (Fmt.str "expected float, got %S" s));
13721365 base_enc = string_of_float;
13731366 }
13741367···13811374 match String.lowercase_ascii s with
13821375 | "true" -> Ok true
13831376 | "false" -> Ok false
13841384- | _ -> Error (Printf.sprintf "expected boolean, got %S" s));
13771377+ | _ -> Error (Fmt.str "expected boolean, got %S" s));
13851378 base_enc = string_of_bool;
13861379 }
13871380···1490148314911484let decode_stream codec s =
14921485 match P.skip_preamble s with
14931493- | Error e -> Error (Printf.sprintf "parse error: %s" e)
14861486+ | Error e -> Error (Fmt.str "parse error: %s" e)
14941487 | Ok () -> (
14951488 if P.at_end s then Error "parse error: empty document: no root element"
14961489 else
14971490 match P.parse_start_tag s with
14981498- | Error e -> Error (Printf.sprintf "parse error: %s" e)
14911491+ | Error e -> Error (Fmt.str "parse error: %s" e)
14991492 | Ok (tag, attrs, self_close) -> (
15001493 match dec_stream codec s ~tag ~attrs ~self_close with
15011494 | Error e -> Error e
···1508150115091502let encode_string ?(indent = 0) codec v =
15101503 let buf = Buffer.create 256 in
15111511- let e = make_encoder ~indent (Buffer.add_string buf) in
15041504+ let e = encoder ~indent (Buffer.add_string buf) in
15121505 enc_value codec e v;
15131506 Buffer.contents buf
15141507···15171510 decode_stream codec stream
1518151115191512let encode ?(indent = 0) codec v writer =
15201520- let e = make_encoder ~indent (Bytes.Writer.write_string writer) in
15131513+ let e = encoder ~indent (Bytes.Writer.write_string writer) in
15211514 enc_value codec e v
1522151515231516(* ── Queries ─────────────────────────────────────────────────────────── *)
1524151715251525-let get_child tag c =
15181518+let child tag c =
15261519 (* Build an El with a single required child field that extracts the
15271520 child with the given tag and decodes it with c. The El uses an
15281521 empty-string sentinel tag so it matches any outer element. *)
···15351528 el_needs_children = true;
15361529 } )
1537153015381538-let get_attr name =
15311531+let attr name =
15391532 (* Build an El with a single required attribute field *)
15401533 let id = Type.Id.make () in
15411534 El
···15461539 el_needs_children = false;
15471540 } )
1548154115491549-let get_nth n c =
15421542+let nth n c =
15501543 (* Map over a List codec that extracts the nth child element *)
15511544 Map
15521545 {
···15571550 | Some v -> Ok v
15581551 | None ->
15591552 Error
15601560- (Printf.sprintf
15611561- "index %d out of bounds (element has %d children)" n
15531553+ (Fmt.str "index %d out of bounds (element has %d children)" n
15621554 (List.length items)));
15631555 map_enc = (fun v -> [ v ]);
15641556 }
···15821574 match dec_tree c child_el with
15831575 | Ok v -> (
15841576 let buf = Buffer.create 64 in
15851585- let e =
15861586- make_encoder ~indent:0 (Buffer.add_string buf)
15871587- in
15771577+ let e = encoder ~indent:0 (Buffer.add_string buf) in
15881578 enc_start_tag e tag;
15891579 enc_value c e v;
15901580 if e.in_start_tag then enc_end_tag_empty e
+13-10
lib/xmlt.mli
···3232 {v
3333 let () =
3434 match Xmlt.decode_string person "<person name=\"Alice\" age=\"30\"/>" with
3535- | Ok p -> Printf.printf "Name: %s\n" p.name
3535+ | Ok p -> Fmt.pr "Name: %s\n" p.name
3636 | Error e -> prerr_endline e
3737 v}
3838···65656666 A value of type ['a t] can decode XML elements to type ['a] and encode
6767 values of type ['a] to XML elements. *)
6868+6969+val pp : 'a t Fmt.t
7070+(** [pp] pretty-prints the codec structure (for debugging). *)
68716972val string : string t
7073(** Codec for text content as a string. *)
···268271 equivalent of Jsont's "soup" approach: they navigate into the structure of
269272 an already-parsed element. *)
270273271271-val get_child : string -> 'a t -> 'a t
272272-(** [get_child tag c] queries a child element by tag name. On decoding, finds
273273- the first direct child element with [tag] and decodes it with [c]. Other
274274+val child : string -> 'a t -> 'a t
275275+(** [child tag c] queries a child element by tag name. On decoding, finds the
276276+ first direct child element with [tag] and decodes it with [c]. Other
274277 children are ignored. Errors if no child with that tag exists. *)
275278276276-val get_attr : string -> string t
277277-(** [get_attr name] queries an attribute value. On decoding, extracts the string
279279+val attr : string -> string t
280280+(** [attr name] queries an attribute value. On decoding, extracts the string
278281 value of attribute [name] from the element. Errors if the attribute is
279282 absent. *)
280283281281-val get_nth : int -> 'a t -> 'a t
282282-(** [get_nth n c] queries the [n]th child element. On decoding, collects all
283283- child elements, decodes them with [c], and returns the [n]th one. Errors if
284284- [n] is out of bounds. *)
284284+val nth : int -> 'a t -> 'a t
285285+(** [nth n c] queries the [n]th child element. On decoding, collects all child
286286+ elements, decodes them with [c], and returns the [n]th one. Errors if [n] is
287287+ out of bounds. *)
285288286289(** {1:updates Updates} *)
287290