···1011```ocaml
12# open Jsont_pointer;;
013# let parse_json s =
14 match Jsont_bytesrw.decode_string Jsont.json s with
15 | Ok json -> json
···20 | Ok s -> s
21 | Error e -> failwith e;;
22val json_to_string : Jsont.json -> string = <fun>
23-# let show_pointer p =
24- let idxs = indices p in
25- let show_index = function
26- | `Mem s -> "Mem:" ^ s
27- | `Nth n -> "Nth:" ^ string_of_int n
28- | `End -> "End"
29- in
30- "[" ^ String.concat ", " (List.map show_index idxs) ^ "]";;
31-val show_pointer : t -> string = <fun>
32```
3334## What is JSON Pointer?
···7172```ocaml
73# let ptr = of_string "/users/0/name";;
74-val ptr : t = <abstr>
75# get ptr users_json;;
76- : Jsont.json = Jsont.String ("Alice", <abstr>)
77```
···101Let's see this in action:
102103```ocaml
104-# let empty_ptr = of_string "";;
105-val empty_ptr : t = <abstr>
106-# show_pointer empty_ptr;;
107-- : string = "[]"
108```
109110The empty pointer has no reference tokens - it points to the root.
111112```ocaml
113-# let foo_ptr = of_string "/foo";;
114-val foo_ptr : t = <abstr>
115-# show_pointer foo_ptr;;
116-- : string = "[Mem:foo]"
117```
118119The pointer `/foo` has one token: `foo`. Since it's not a number, it's
120interpreted as an object member name (`Mem`).
121122```ocaml
123-# let foo_0_ptr = of_string "/foo/0";;
124-val foo_0_ptr : t = <abstr>
125-# show_pointer foo_0_ptr;;
126-- : string = "[Mem:foo, Nth:0]"
127```
128129Here we have two tokens: `foo` (a member name) and `0` (interpreted as
130an array index `Nth`).
131132```ocaml
133-# show_pointer (of_string "/foo/bar/baz");;
134-- : string = "[Mem:foo, Mem:bar, Mem:baz]"
135```
136137Multiple tokens navigate deeper into nested structures.
···171- : (t, string) result =
172Error "Invalid JSON Pointer: must be empty or start with '/': foo"
173# of_string_result "/valid";;
174-- : (t, string) result = Ok <abstr>
175```
176177## Evaluation: Navigating JSON
···285286```ocaml
287# let slash_ptr = make [`Mem "a/b"];;
288-val slash_ptr : t = <abstr>
289# to_string slash_ptr;;
290- : string = "/a~1b"
291# get slash_ptr rfc_example |> json_to_string;;
···358> note that leading zeros are not allowed
359360```ocaml
361-# show_pointer (of_string "/foo/0");;
362-- : string = "[Mem:foo, Nth:0]"
363```
364365Zero itself is fine.
366367```ocaml
368-# show_pointer (of_string "/foo/01");;
369-- : string = "[Mem:foo, Mem:01]"
370```
371372But `01` has a leading zero, so it's NOT treated as an array index - it
···384how it parses:
385386```ocaml
387-# show_pointer (of_string "/foo/-");;
388-- : string = "[Mem:foo, End]"
389```
390391The `-` is recognized as a special `End` index.
···562563```ocaml
564# let p = make [`Mem "a/b"];;
565-val p : t = <abstr>
566# to_string p;;
567- : string = "/a~1b"
568-# let p' = of_string "/a~1b";;
569-val p' : t = <abstr>
570-# show_pointer p';;
571-- : string = "[Mem:a/b]"
572```
573574### Escaping in Action
···663664```ocaml
665# let port_ptr = make [`Mem "database"; `Mem "port"];;
666-val port_ptr : t = <abstr>
667# to_string port_ptr;;
668- : string = "/database/port"
669```
···672673```ocaml
674# let first_feature_ptr = make [`Mem "features"; `Nth 0];;
675-val first_feature_ptr : t = <abstr>
676# to_string first_feature_ptr;;
677- : string = "/features/0"
678```
···683684```ocaml
685# let db_ptr = of_string "/database";;
686-val db_ptr : t = <abstr>
687# let creds_ptr = append db_ptr (`Mem "credentials");;
688-val creds_ptr : t = <abstr>
689# let user_ptr = append creds_ptr (`Mem "username");;
690-val user_ptr : t = <abstr>
691# to_string user_ptr;;
692- : string = "/database/credentials/username"
693```
···696697```ocaml
698# let base = of_string "/api/v1";;
699-val base : t = <abstr>
700# let endpoint = of_string "/users/0";;
701-val endpoint : t = <abstr>
702# to_string (concat base endpoint);;
703- : string = "/api/v1/users/0"
704```
···1011```ocaml
12# open Jsont_pointer;;
13+# #install_printer Jsont_pointer_top.printer;;
14# let parse_json s =
15 match Jsont_bytesrw.decode_string Jsont.json s with
16 | Ok json -> json
···21 | Ok s -> s
22 | Error e -> failwith e;;
23val json_to_string : Jsont.json -> string = <fun>
00000000024```
2526## What is JSON Pointer?
···6364```ocaml
65# let ptr = of_string "/users/0/name";;
66+val ptr : t = [`Mem "users"; `Nth 0; `Mem "name"]
67# get ptr users_json;;
68- : Jsont.json = Jsont.String ("Alice", <abstr>)
69```
···93Let's see this in action:
9495```ocaml
96+# of_string "";;
97+- : t = []
0098```
99100The empty pointer has no reference tokens - it points to the root.
101102```ocaml
103+# of_string "/foo";;
104+- : t = [`Mem "foo"]
00105```
106107The pointer `/foo` has one token: `foo`. Since it's not a number, it's
108interpreted as an object member name (`Mem`).
109110```ocaml
111+# of_string "/foo/0";;
112+- : t = [`Mem "foo"; `Nth 0]
00113```
114115Here we have two tokens: `foo` (a member name) and `0` (interpreted as
116an array index `Nth`).
117118```ocaml
119+# of_string "/foo/bar/baz";;
120+- : t = [`Mem "foo"; `Mem "bar"; `Mem "baz"]
121```
122123Multiple tokens navigate deeper into nested structures.
···157- : (t, string) result =
158Error "Invalid JSON Pointer: must be empty or start with '/': foo"
159# of_string_result "/valid";;
160+- : (t, string) result = Ok [`Mem "valid"]
161```
162163## Evaluation: Navigating JSON
···271272```ocaml
273# let slash_ptr = make [`Mem "a/b"];;
274+val slash_ptr : t = [`Mem "a/b"]
275# to_string slash_ptr;;
276- : string = "/a~1b"
277# get slash_ptr rfc_example |> json_to_string;;
···344> note that leading zeros are not allowed
345346```ocaml
347+# of_string "/foo/0";;
348+- : t = [`Mem "foo"; `Nth 0]
349```
350351Zero itself is fine.
352353```ocaml
354+# of_string "/foo/01";;
355+- : t = [`Mem "foo"; `Mem "01"]
356```
357358But `01` has a leading zero, so it's NOT treated as an array index - it
···370how it parses:
371372```ocaml
373+# of_string "/foo/-";;
374+- : t = [`Mem "foo"; `End]
375```
376377The `-` is recognized as a special `End` index.
···548549```ocaml
550# let p = make [`Mem "a/b"];;
551+val p : t = [`Mem "a/b"]
552# to_string p;;
553- : string = "/a~1b"
554+# of_string "/a~1b";;
555+- : t = [`Mem "a/b"]
00556```
557558### Escaping in Action
···647648```ocaml
649# let port_ptr = make [`Mem "database"; `Mem "port"];;
650+val port_ptr : t = [`Mem "database"; `Mem "port"]
651# to_string port_ptr;;
652- : string = "/database/port"
653```
···656657```ocaml
658# let first_feature_ptr = make [`Mem "features"; `Nth 0];;
659+val first_feature_ptr : t = [`Mem "features"; `Nth 0]
660# to_string first_feature_ptr;;
661- : string = "/features/0"
662```
···667668```ocaml
669# let db_ptr = of_string "/database";;
670+val db_ptr : t = [`Mem "database"]
671# let creds_ptr = append db_ptr (`Mem "credentials");;
672+val creds_ptr : t = [`Mem "database"; `Mem "credentials"]
673# let user_ptr = append creds_ptr (`Mem "username");;
674+val user_ptr : t = [`Mem "database"; `Mem "credentials"; `Mem "username"]
675# to_string user_ptr;;
676- : string = "/database/credentials/username"
677```
···680681```ocaml
682# let base = of_string "/api/v1";;
683+val base : t = [`Mem "api"; `Mem "v1"]
684# let endpoint = of_string "/users/0";;
685+val endpoint : t = [`Mem "users"; `Nth 0]
686# to_string (concat base endpoint);;
687- : string = "/api/v1/users/0"
688```
+10
src/jsont_pointer.ml
···253let pp ppf p =
254 Format.pp_print_string ppf (to_string p)
2550000000000256(* Comparison *)
257258let segment_equal s1 s2 = match s1, s2 with
···253let pp ppf p =
254 Format.pp_print_string ppf (to_string p)
255256+let pp_verbose ppf p =
257+ let pp_index ppf = function
258+ | `Mem s -> Format.fprintf ppf "`Mem %S" s
259+ | `Nth n -> Format.fprintf ppf "`Nth %d" n
260+ | `End -> Format.fprintf ppf "`End"
261+ in
262+ Format.fprintf ppf "[%a]"
263+ (Format.pp_print_list ~pp_sep:(fun ppf () -> Format.fprintf ppf "; ") pp_index)
264+ (indices p)
265+266(* Comparison *)
267268let segment_equal s1 s2 = match s1, s2 with
+5
src/jsont_pointer.mli
···189val pp : Format.formatter -> t -> unit
190(** [pp] formats a pointer using {!to_string}. *)
19100000192(** {2:comparison Comparison} *)
193194val equal : t -> t -> bool
···189val pp : Format.formatter -> t -> unit
190(** [pp] formats a pointer using {!to_string}. *)
191192+val pp_verbose : Format.formatter -> t -> unit
193+(** [pp_verbose] formats a pointer showing its index structure.
194+ For example, [/foo/0/-] is formatted as [[`Mem "foo"; `Nth 0; `End]].
195+ Useful for debugging and understanding pointer structure. *)
196+197(** {2:comparison Comparison} *)
198199val equal : t -> t -> bool