A arbitrary JSON parser for golang.
- Standalone: implement the parser independently for
ECMA-404 The JSON Data Interchange Standard. - Fast: about two times faster than the package
go-simplejsonwhich use nativeencoding/jsonlibrary. - Lightweight: only about 500 rows code for parser include UTF-16 pairs covert to UTF-8 bytes.
go get github.com/acrazing/cheapjsonpackage main
import (
"github.com/acrazing/cheapjson""encoding/json"
)
funcmain() {
// Unmarshal a bytes slicevalue, err:=cheapjson.Unmarshal([]byte("{\"hello\":\"world\", \"int\":12345}"))
iferr!=nil {
panic(err)
}
// type checkif!value.IsObject() {
panic("parse error")
}
// get a child fieldstr:=value.Get("hello")
// get as stringprintln(str.String()) // world// get as intprintln(value.Get("int").Int()) // 12345// And any else you can do:_=value.Float() // returns float64_=value.Array() // returns []*Value_=value.Object() // returns map[string]*Value// WARNING: any of the upon value extract operate// need to check the type at first as follow:ifvalue.IsObject() {
// value is a object, and then you can operate:_=value.Object()
}
// And there are more type checks_=value.IsObject()
_=value.IsArray()
_=value.IsNumber() // if is float or int, returns true_=value.IsInt() // just check is int_=value.IsTrue()
_=value.IsFalse()
_=value.IsBool()
_=value.IsNull()
_=value.IsString()
// And you can manipulate a valuevalue=cheapjson.NewValue()
value.AsObject(nil) // set as a object_=value.AddField("hello") // if a value is a object, you can call this, else will panicvalue.AsArray(nil) // set as a arrayelem:=value.AddElement() // if a value is a array, yu can call this, else will panicelem.AsInt(12) // as a intelem.AsFloat(232)
elem.AsBool(true)
elem.AsNull()
// And you can get a deep path by:field:=elem.Get("hello", "world", "deep", "3")
_=field.Value()
// Or set a deep path// The different between Get and Ensure is that the Get// just returns the exists field, if the path does not exist// will return nil, and it will covert the path to integer// if the node is an array, and the Ensure will force the// path to be an object, and if the target path does not exist// will auto generate it as a empty node.value.Ensure("hello", "world", "deep", "3").AsInt(3)
// And you can dump a value to raw structdata:=value.Value()
// and this could be json marshal_, _=json.Marshal(data)
}See parser_test.go, compare with go-simplejson, which
use the native encoding/json library to unmarshal a json. The result is:
- NormalInput(small): about 1.6 times faster
- BigInput: about 4.4 times faster
- DeepInput: about 7 times faster
go test -bench=. -v ./parser_test.go
# 2017/07/22 12:48:45 big input size: 92338772, normal input size: 763, deep input size: 33976002# === RUN TestUnmarshal# --- PASS: TestUnmarshal (0.00s)# === RUN TestSimpleJson# --- PASS: TestSimpleJson (1.62s)# BenchmarkUnmarshalBigInput-4 5 358595392 ns/op# BenchmarkSimpleJsonBigInput-4 1 1560047078 ns/op# BenchmarkUnmarshalNormalInput-4 200000 5372 ns/op# BenchmarkSimpleJsonNormalInput-4 200000 8593 ns/op# BenchmarkUnmarshalDeepInput-4 30 42870590 ns/op# BenchmarkSimpleJsonDeepInput-4 5 305351224 ns/op# PASS# ok command-line-arguments 18.314sMIT
- more unit test.
- test the performance about make buffer before handle a string, (will walk the string twice).