···11```ocaml
12# open Jsont_pointer;;
13# #install_printer Jsont_pointer_top.printer;;
14+# #install_printer Jsont_pointer_top.json_printer;;
15# let parse_json s =
16 match Jsont_bytesrw.decode_string Jsont.json s with
17 | Ok json -> json
18 | Error e -> failwith e;;
19val parse_json : string -> Jsont.json = <fun>
0000020```
2122## What is JSON Pointer?
···40 ]
41 }|};;
42val users_json : Jsont.json =
43+ {"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}
00000000000044```
4546The JSON Pointer `/users/0/name` refers to the string `"Alice"`:
···49# let ptr = of_string "/users/0/name";;
50val ptr : t = [`Mem "users"; `Nth 0; `Mem "name"]
51# get ptr users_json;;
52+- : Jsont.json = "Alice"
53```
5455In OCaml, this is represented by the `Jsont_pointer.t` type - a sequence
···170 "m~n": 8
171 }|};;
172val rfc_example : Jsont.json =
173+ {"foo":["bar","baz"],"":0,"a/b":1,"c%d":2,"e^f":3,"g|h":4,"i\\j":5,"k\"l":6," ":7,"m~n":8}
00000000000000174```
175176This document is carefully constructed to exercise various edge cases!
···178### The Root Pointer
179180```ocaml
181+# get root rfc_example ;;
182+- : Jsont.json =
183+{"foo":["bar","baz"],"":0,"a/b":1,"c%d":2,"e^f":3,"g|h":4,"i\\j":5,"k\"l":6," ":7,"m~n":8}
184```
185186The empty pointer (`root`) returns the whole document.
···188### Object Member Access
189190```ocaml
191+# get (of_string "/foo") rfc_example ;;
192+- : Jsont.json = ["bar","baz"]
193```
194195`/foo` accesses the member named `foo`, which is an array.
···197### Array Index Access
198199```ocaml
200+# get (of_string "/foo/0") rfc_example ;;
201+- : Jsont.json = "bar"
202+# get (of_string "/foo/1") rfc_example ;;
203+- : Jsont.json = "baz"
204```
205206`/foo/0` first goes to `foo`, then accesses index 0 of the array.
···210JSON allows empty strings as object keys:
211212```ocaml
213+# get (of_string "/") rfc_example ;;
214+- : Jsont.json = 0
215```
216217The pointer `/` has one token: the empty string. This accesses the member
···222The RFC example includes keys with `/` and `~` characters:
223224```ocaml
225+# get (of_string "/a~1b") rfc_example ;;
226+- : Jsont.json = 1
227```
228229The token `a~1b` refers to the key `a/b`. We'll explain this escaping
230[below](#escaping-special-characters).
231232```ocaml
233+# get (of_string "/m~0n") rfc_example ;;
234+- : Jsont.json = 8
235```
236237The token `m~0n` refers to the key `m~n`.
···244val slash_ptr : t = [`Mem "a/b"]
245# to_string slash_ptr;;
246- : string = "/a~1b"
247+# get slash_ptr rfc_example ;;
248+- : Jsont.json = 1
249```
250251The library escapes it when converting to string.
···255Most characters don't need escaping in JSON Pointer strings:
256257```ocaml
258+# get (of_string "/c%d") rfc_example ;;
259+- : Jsont.json = 2
260+# get (of_string "/e^f") rfc_example ;;
261+- : Jsont.json = 3
262+# get (of_string "/g|h") rfc_example ;;
263+- : Jsont.json = 4
264+# get (of_string "/ ") rfc_example ;;
265+- : Jsont.json = 7
266```
267268Even a space is a valid key character!
···374375```ocaml
376# let obj = parse_json {|{"foo":"bar"}|};;
377+val obj : Jsont.json = {"foo":"bar"}
0378# add (of_string "/baz") obj ~value:(Jsont.Json.string "qux")
379+ ;;
380+- : Jsont.json = {"foo":"bar","baz":"qux"}
381```
382383For arrays, `add` inserts BEFORE the specified index:
384385```ocaml
386# let arr_obj = parse_json {|{"foo":["a","b"]}|};;
387+val arr_obj : Jsont.json = {"foo":["a","b"]}
00000388# add (of_string "/foo/1") arr_obj ~value:(Jsont.Json.string "X")
389+ ;;
390+- : Jsont.json = {"foo":["a","X","b"]}
391```
392393This is where the `-` marker shines - it appends to the end:
394395```ocaml
396# add (of_string "/foo/-") arr_obj ~value:(Jsont.Json.string "c")
397+ ;;
398+- : Jsont.json = {"foo":["a","b","c"]}
399```
400401### Remove
···404405```ocaml
406# let two_fields = parse_json {|{"foo":"bar","baz":"qux"}|};;
407+val two_fields : Jsont.json = {"foo":"bar","baz":"qux"}
408+# remove (of_string "/baz") two_fields ;;
409+- : Jsont.json = {"foo":"bar"}
0000410```
411412For arrays, it removes and shifts:
413414```ocaml
415# let three_elem = parse_json {|{"foo":["a","b","c"]}|};;
416+val three_elem : Jsont.json = {"foo":["a","b","c"]}
417+# remove (of_string "/foo/1") three_elem ;;
418+- : Jsont.json = {"foo":["a","c"]}
0000000419```
420421### Replace
···424425```ocaml
426# replace (of_string "/foo") obj ~value:(Jsont.Json.string "baz")
427+ ;;
428+- : Jsont.json = {"foo":"baz"}
429```
430431Unlike `add`, `replace` requires the target to already exist.
···437438```ocaml
439# let nested = parse_json {|{"foo":{"bar":"baz"},"qux":{}}|};;
440+val nested : Jsont.json = {"foo":{"bar":"baz"},"qux":{}}
000000441# move ~from:(of_string "/foo/bar") ~path:(of_string "/qux/thud") nested
442+ ;;
443+- : Jsont.json = {"foo":{},"qux":{"thud":"baz"}}
444```
445446### Copy
···449450```ocaml
451# let to_copy = parse_json {|{"foo":{"bar":"baz"}}|};;
452+val to_copy : Jsont.json = {"foo":{"bar":"baz"}}
00000453# copy ~from:(of_string "/foo/bar") ~path:(of_string "/foo/qux") to_copy
454+ ;;
455+- : Jsont.json = {"foo":{"bar":"baz","qux":"baz"}}
456```
457458### Test
···646 "features": ["auth", "logging", "metrics"]
647 }|};;
648val config_json : Jsont.json =
649+ {"database":{"host":"localhost","port":5432,"credentials":{"username":"admin","password":"secret"}},"features":["auth","logging","metrics"]}
0000000000000000650```
651652### Typed Access with `path`
···704 }
705 }|};;
706val org_json : Jsont.json =
707+ {"organization":{"owner":{"name":"Alice","email":"alice@example.com","age":35},"members":[{"name":"Bob","email":"bob@example.com","age":28}]}}
00000000000000000000708# Jsont.Json.decode
709 (path (of_string "/organization/owner/name") Jsont.string)
710 org_json
+1-1
src/jsont_pointer.ml
···255256let 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
···255256let 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