+1
-1
doc/dune
+1
-1
doc/dune
+28
-44
doc/tutorial.md
+28
-44
doc/tutorial.md
···
10
11
```ocaml
12
# open Jsont_pointer;;
13
# 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;;
22
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
```
33
34
## What is JSON Pointer?
···
71
72
```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
```
···
101
Let's see this in action:
102
103
```ocaml
104
-
# let empty_ptr = of_string "";;
105
-
val empty_ptr : t = <abstr>
106
-
# show_pointer empty_ptr;;
107
-
- : string = "[]"
108
```
109
110
The empty pointer has no reference tokens - it points to the root.
111
112
```ocaml
113
-
# let foo_ptr = of_string "/foo";;
114
-
val foo_ptr : t = <abstr>
115
-
# show_pointer foo_ptr;;
116
-
- : string = "[Mem:foo]"
117
```
118
119
The pointer `/foo` has one token: `foo`. Since it's not a number, it's
120
interpreted as an object member name (`Mem`).
121
122
```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
```
128
129
Here we have two tokens: `foo` (a member name) and `0` (interpreted as
130
an array index `Nth`).
131
132
```ocaml
133
-
# show_pointer (of_string "/foo/bar/baz");;
134
-
- : string = "[Mem:foo, Mem:bar, Mem:baz]"
135
```
136
137
Multiple tokens navigate deeper into nested structures.
···
171
- : (t, string) result =
172
Error "Invalid JSON Pointer: must be empty or start with '/': foo"
173
# of_string_result "/valid";;
174
-
- : (t, string) result = Ok <abstr>
175
```
176
177
## Evaluation: Navigating JSON
···
285
286
```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
359
360
```ocaml
361
-
# show_pointer (of_string "/foo/0");;
362
-
- : string = "[Mem:foo, Nth:0]"
363
```
364
365
Zero itself is fine.
366
367
```ocaml
368
-
# show_pointer (of_string "/foo/01");;
369
-
- : string = "[Mem:foo, Mem:01]"
370
```
371
372
But `01` has a leading zero, so it's NOT treated as an array index - it
···
384
how it parses:
385
386
```ocaml
387
-
# show_pointer (of_string "/foo/-");;
388
-
- : string = "[Mem:foo, End]"
389
```
390
391
The `-` is recognized as a special `End` index.
···
562
563
```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
```
573
574
### Escaping in Action
···
663
664
```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
```
···
672
673
```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
```
···
683
684
```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
```
···
696
697
```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
```
···
10
11
```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;;
23
val json_to_string : Jsont.json -> string = <fun>
24
```
25
26
## What is JSON Pointer?
···
63
64
```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
```
···
93
Let's see this in action:
94
95
```ocaml
96
+
# of_string "";;
97
+
- : t = []
98
```
99
100
The empty pointer has no reference tokens - it points to the root.
101
102
```ocaml
103
+
# of_string "/foo";;
104
+
- : t = [`Mem "foo"]
105
```
106
107
The pointer `/foo` has one token: `foo`. Since it's not a number, it's
108
interpreted as an object member name (`Mem`).
109
110
```ocaml
111
+
# of_string "/foo/0";;
112
+
- : t = [`Mem "foo"; `Nth 0]
113
```
114
115
Here we have two tokens: `foo` (a member name) and `0` (interpreted as
116
an array index `Nth`).
117
118
```ocaml
119
+
# of_string "/foo/bar/baz";;
120
+
- : t = [`Mem "foo"; `Mem "bar"; `Mem "baz"]
121
```
122
123
Multiple tokens navigate deeper into nested structures.
···
157
- : (t, string) result =
158
Error "Invalid JSON Pointer: must be empty or start with '/': foo"
159
# of_string_result "/valid";;
160
+
- : (t, string) result = Ok [`Mem "valid"]
161
```
162
163
## Evaluation: Navigating JSON
···
271
272
```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
345
346
```ocaml
347
+
# of_string "/foo/0";;
348
+
- : t = [`Mem "foo"; `Nth 0]
349
```
350
351
Zero itself is fine.
352
353
```ocaml
354
+
# of_string "/foo/01";;
355
+
- : t = [`Mem "foo"; `Mem "01"]
356
```
357
358
But `01` has a leading zero, so it's NOT treated as an array index - it
···
370
how it parses:
371
372
```ocaml
373
+
# of_string "/foo/-";;
374
+
- : t = [`Mem "foo"; `End]
375
```
376
377
The `-` is recognized as a special `End` index.
···
548
549
```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"]
556
```
557
558
### Escaping in Action
···
647
648
```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
```
···
656
657
```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
```
···
667
668
```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
```
···
680
681
```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
+10
src/jsont_pointer.ml
···
253
let pp ppf p =
254
Format.pp_print_string ppf (to_string p)
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
+
266
(* Comparison *)
267
268
let segment_equal s1 s2 = match s1, s2 with
+5
src/jsont_pointer.mli
+5
src/jsont_pointer.mli
···
189
val pp : Format.formatter -> t -> unit
190
(** [pp] formats a pointer using {!to_string}. *)
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
+
197
(** {2:comparison Comparison} *)
198
199
val equal : t -> t -> bool