+1
-1
doc/dune
+1
-1
doc/dune
+28
-44
doc/tutorial.md
+28
-44
doc/tutorial.md
···
10
10
11
11
```ocaml
12
12
# open Jsont_pointer;;
13
+
# #install_printer Jsont_pointer_top.printer;;
13
14
# let parse_json s =
14
15
match Jsont_bytesrw.decode_string Jsont.json s with
15
16
| Ok json -> json
···
20
21
| Ok s -> s
21
22
| Error e -> failwith e;;
22
23
val 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
24
```
33
25
34
26
## What is JSON Pointer?
···
71
63
72
64
```ocaml
73
65
# let ptr = of_string "/users/0/name";;
74
-
val ptr : t = <abstr>
66
+
val ptr : t = [`Mem "users"; `Nth 0; `Mem "name"]
75
67
# get ptr users_json;;
76
68
- : Jsont.json = Jsont.String ("Alice", <abstr>)
77
69
```
···
101
93
Let's see this in action:
102
94
103
95
```ocaml
104
-
# let empty_ptr = of_string "";;
105
-
val empty_ptr : t = <abstr>
106
-
# show_pointer empty_ptr;;
107
-
- : string = "[]"
96
+
# of_string "";;
97
+
- : t = []
108
98
```
109
99
110
100
The empty pointer has no reference tokens - it points to the root.
111
101
112
102
```ocaml
113
-
# let foo_ptr = of_string "/foo";;
114
-
val foo_ptr : t = <abstr>
115
-
# show_pointer foo_ptr;;
116
-
- : string = "[Mem:foo]"
103
+
# of_string "/foo";;
104
+
- : t = [`Mem "foo"]
117
105
```
118
106
119
107
The pointer `/foo` has one token: `foo`. Since it's not a number, it's
120
108
interpreted as an object member name (`Mem`).
121
109
122
110
```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]"
111
+
# of_string "/foo/0";;
112
+
- : t = [`Mem "foo"; `Nth 0]
127
113
```
128
114
129
115
Here we have two tokens: `foo` (a member name) and `0` (interpreted as
130
116
an array index `Nth`).
131
117
132
118
```ocaml
133
-
# show_pointer (of_string "/foo/bar/baz");;
134
-
- : string = "[Mem:foo, Mem:bar, Mem:baz]"
119
+
# of_string "/foo/bar/baz";;
120
+
- : t = [`Mem "foo"; `Mem "bar"; `Mem "baz"]
135
121
```
136
122
137
123
Multiple tokens navigate deeper into nested structures.
···
171
157
- : (t, string) result =
172
158
Error "Invalid JSON Pointer: must be empty or start with '/': foo"
173
159
# of_string_result "/valid";;
174
-
- : (t, string) result = Ok <abstr>
160
+
- : (t, string) result = Ok [`Mem "valid"]
175
161
```
176
162
177
163
## Evaluation: Navigating JSON
···
285
271
286
272
```ocaml
287
273
# let slash_ptr = make [`Mem "a/b"];;
288
-
val slash_ptr : t = <abstr>
274
+
val slash_ptr : t = [`Mem "a/b"]
289
275
# to_string slash_ptr;;
290
276
- : string = "/a~1b"
291
277
# get slash_ptr rfc_example |> json_to_string;;
···
358
344
> note that leading zeros are not allowed
359
345
360
346
```ocaml
361
-
# show_pointer (of_string "/foo/0");;
362
-
- : string = "[Mem:foo, Nth:0]"
347
+
# of_string "/foo/0";;
348
+
- : t = [`Mem "foo"; `Nth 0]
363
349
```
364
350
365
351
Zero itself is fine.
366
352
367
353
```ocaml
368
-
# show_pointer (of_string "/foo/01");;
369
-
- : string = "[Mem:foo, Mem:01]"
354
+
# of_string "/foo/01";;
355
+
- : t = [`Mem "foo"; `Mem "01"]
370
356
```
371
357
372
358
But `01` has a leading zero, so it's NOT treated as an array index - it
···
384
370
how it parses:
385
371
386
372
```ocaml
387
-
# show_pointer (of_string "/foo/-");;
388
-
- : string = "[Mem:foo, End]"
373
+
# of_string "/foo/-";;
374
+
- : t = [`Mem "foo"; `End]
389
375
```
390
376
391
377
The `-` is recognized as a special `End` index.
···
562
548
563
549
```ocaml
564
550
# let p = make [`Mem "a/b"];;
565
-
val p : t = <abstr>
551
+
val p : t = [`Mem "a/b"]
566
552
# to_string p;;
567
553
- : string = "/a~1b"
568
-
# let p' = of_string "/a~1b";;
569
-
val p' : t = <abstr>
570
-
# show_pointer p';;
571
-
- : string = "[Mem:a/b]"
554
+
# of_string "/a~1b";;
555
+
- : t = [`Mem "a/b"]
572
556
```
573
557
574
558
### Escaping in Action
···
663
647
664
648
```ocaml
665
649
# let port_ptr = make [`Mem "database"; `Mem "port"];;
666
-
val port_ptr : t = <abstr>
650
+
val port_ptr : t = [`Mem "database"; `Mem "port"]
667
651
# to_string port_ptr;;
668
652
- : string = "/database/port"
669
653
```
···
672
656
673
657
```ocaml
674
658
# let first_feature_ptr = make [`Mem "features"; `Nth 0];;
675
-
val first_feature_ptr : t = <abstr>
659
+
val first_feature_ptr : t = [`Mem "features"; `Nth 0]
676
660
# to_string first_feature_ptr;;
677
661
- : string = "/features/0"
678
662
```
···
683
667
684
668
```ocaml
685
669
# let db_ptr = of_string "/database";;
686
-
val db_ptr : t = <abstr>
670
+
val db_ptr : t = [`Mem "database"]
687
671
# let creds_ptr = append db_ptr (`Mem "credentials");;
688
-
val creds_ptr : t = <abstr>
672
+
val creds_ptr : t = [`Mem "database"; `Mem "credentials"]
689
673
# let user_ptr = append creds_ptr (`Mem "username");;
690
-
val user_ptr : t = <abstr>
674
+
val user_ptr : t = [`Mem "database"; `Mem "credentials"; `Mem "username"]
691
675
# to_string user_ptr;;
692
676
- : string = "/database/credentials/username"
693
677
```
···
696
680
697
681
```ocaml
698
682
# let base = of_string "/api/v1";;
699
-
val base : t = <abstr>
683
+
val base : t = [`Mem "api"; `Mem "v1"]
700
684
# let endpoint = of_string "/users/0";;
701
-
val endpoint : t = <abstr>
685
+
val endpoint : t = [`Mem "users"; `Nth 0]
702
686
# to_string (concat base endpoint);;
703
687
- : string = "/api/v1/users/0"
704
688
```
+10
src/jsont_pointer.ml
+10
src/jsont_pointer.ml
···
253
253
let pp ppf p =
254
254
Format.pp_print_string ppf (to_string p)
255
255
256
+
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
+
256
266
(* Comparison *)
257
267
258
268
let segment_equal s1 s2 = match s1, s2 with
+5
src/jsont_pointer.mli
+5
src/jsont_pointer.mli
···
189
189
val pp : Format.formatter -> t -> unit
190
190
(** [pp] formats a pointer using {!to_string}. *)
191
191
192
+
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
+
192
197
(** {2:comparison Comparison} *)
193
198
194
199
val equal : t -> t -> bool