Fast, lightweight JSON encode/decode and query library. It provides an inspectable/mutable JSONTree structure and a powerful QJSON Path query syntax.
- High‑performance parsing: decode raw JSON into traversable
JSONTree/Nodewith object pool reuse to reduce GC pressure. - QJSON Path queries: access by object keys and array indexes; support the
#selector and filters (==,=,!==,!=,>,>=,<,<=), plus escaped dots in keys. - In‑place mutation: set values via
SetString/SetInt/SetBool/SetFloat, remove object keys and array elements. - Readable output: ANSI colored output via
ColorfulMarshalandColorfulMarshalWithIndentfor terminal UX. - Encoding interoperability:
json.Marshal/Unmarshalworks directly onJSONTree; convert any Go object viaConvertToJSONTree. - Equality and hashing: structural equality with
Equal()and stable hashes withHash()/Rehash(). - Diff:
Diff()produces a list of differences between two trees, useful for change audits and test comparisons. - Zero external dependencies: standard library only (Go ≥ 1.13).
go get -u github.com/qjpcpu/qjson@latestpackage main
import (
"encoding/json"
"fmt"
qjson "github.com/qjpcpu/qjson"
)
func main() {
// Parse
tree, err := qjson.Decode([]byte(`{"name":{"first":"Tom","last":"Anderson"},"age":37}`))
if err != nil { panic(err) }
// Query
fmt.Println(tree.Find("name.last").AsString()) // Anderson
fmt.Println(tree.Find("age").AsInt()) // 37
// Mutate
tree.Find("name.first").SetString("Link")
tree.Find("age").SetInt(12)
// Encode (std lib)
data, _ := json.Marshal(tree)
fmt.Println(string(data)) // {"name":{"first":"Link","last":"Anderson"},"age":12}
// Color output
fmt.Println(string(tree.ColorfulMarshal()))
}- Basics: use
.to access object keys or array indexesname.last→ "Anderson"children.1→ "Alex"
- Selector
#: project or filter arraysfriends.#.age→[44,68,47]
- Filters inside
#(...)- Contains:
#(=c); Equals:#(==c); Not contains:#(!=c); Not equals:#(!==c) - Comparisons:
age>47,age>=47,age<47,age<=47 - Nested:
friends.#(nets.#(=="fb"))
- Contains:
- Escaping: keys containing
.must escape the dot, e.g.fav\.movieor raw string literalfav\.movie
// Modify
tree.Find(`name.first`).SetString("Link")
tree.Find(`age`).SetInt(12)
// Remove object key
tree.Remove(`name.last`)
// Remove array element; clear array
tree.Remove(`children.0`)
tree.Remove(`children.#`)// Any object → JSONTree
tree, err := qjson.ConvertToJSONTree(&struct{ X string `json:"x"` }{X:"1"})
// JSONTree ↔ std lib
var t qjson.JSONTree
json.Unmarshal([]byte(`{"a":1}`), &t)
data, _ := json.Marshal(&t)// Non‑indented color
fmt.Println(string(tree.ColorfulMarshal()))
// Indented color
fmt.Println(string(tree.ColorfulMarshalWithIndent()))t1, _ := qjson.Decode([]byte(`{"a":1}`))
t2, _ := qjson.Decode([]byte(`{"a":1}`))
fmt.Println(t1.Equal(t2)) // true
fmt.Println(t1.Root.Hash()) // structural hash
// Diff
items := qjson.Diff(t1, t2)
fmt.Println(items.Exist()) // any differences
fmt.Println(items.String()) // human‑readable diff- Object pools and compact data structures improve parsing and manipulation performance.
- Run benchmarks:
go test -bench=. -benchmem- Run:
go test ./... -cover- Coverage: use the printed result (e.g. 87%+) from your environment.
- Optional: enable Codecov by adding
CODECOV_TOKENsecret and check the badge on PRs.
- Go 1.13 and above.
- Standard library only, no external dependencies.
- Path syntax includes escaping and filter expressions; validate complex paths in tests first.
unsafeconversions between string and []byte are used to reduce copies; ensure it fits your environment.- ANSI color output may not render in some terminals.
MIT — see LICENSE.