Resolve or set a value inside a nested map[string]any document by RFC 6901
JSON Pointer path (e.g. /importer/address/district).
Pointer syntax and escaping follow RFC 6901
in full: a pointer is a sequence of /-prefixed segments, ~1 and ~0 decode
to / and ~ respectively, and the empty string denotes the whole document
(the root). This package treats the root pointer as invalid input, since Get
and Set exist to address a value inside a document, not the document
itself — see Limitations.
Get and Set only ever walk into map[string]any. They stop, without
error, the moment they meet anything else — including a []any slice —
before the pointer is exhausted. So while the pointer syntax supports
array indices (e.g. /items/0), this package does not resolve them today:
Get on such a pointer reports ok=false once it reaches the slice.
Other current limitations:
- The empty (root) pointer is always rejected by
Valid/Segments/Get/Set, even though RFC 6901 defines it as a legal pointer to the whole document. - No
json.RawMessage/[]byteconvenience — callers must already have a decodedmap[string]any(e.g. viaencoding/jsonorjson.Decoder.UseNumber()for numeric precision).
- Array indexing. Extending
Get/Setto walk into[]anyon a numeric segment (with RFC 6901's-meaning "one past the last element" for appends inSet). Nothing about the pointer syntax needs to change for this — only the walk inGet/Set— so existing pointers keep working unchanged once it lands. - Revisiting root-pointer support if a caller needs to address the whole document rather than a field inside it.
import "github.com/OpenNSW/core/json/jsonpointer"
doc := map[string]any{
"importer": map[string]any{
"address": map[string]any{
"district": "Gampaha",
},
},
}
v, ok := jsonpointer.Get(doc, "/importer/address/district") // "Gampaha", true
ok = jsonpointer.Set(doc, "/importer/address/postcode", "10230") // creates nothing new here, just adds a keyValid checks pointer syntax without a document, for validating a pointer
at the time it's authored (e.g. in a config file) rather than the first time
it's used:
jsonpointer.Valid("/importer/address/district") // true
jsonpointer.Valid("no-leading-slash") // falseSegments splits a pointer into its unescaped path segments, for callers
building something other than a Get/Set call out of the path — e.g. a SQL
JSON-path expression:
segments, err := jsonpointer.Segments("/importer/address/district")
// []string{"importer", "address", "district"}, nil