1
0
mirror of https://github.com/json-iterator/go.git synced 2025-01-23 18:54:21 +02:00
json-iterator/README.md

138 lines
3.3 KiB
Markdown
Raw Normal View History

2016-12-04 23:01:42 +08:00
# json iterator (jsoniter)
2016-12-01 00:56:25 +08:00
2016-12-04 23:01:42 +08:00
faster than DOM, more usable than SAX/StAX
2016-12-01 00:56:25 +08:00
2016-12-04 23:01:42 +08:00
for performance numbers, see https://github.com/json-iterator/go-benchmark
2016-12-01 00:56:25 +08:00
2016-12-04 23:01:42 +08:00
# DOM style api
2016-12-01 00:56:25 +08:00
2016-12-05 13:31:59 +08:00
Jsoniter can work as drop in replacement for json.Unmarshal
2016-12-01 00:56:25 +08:00
```
2016-12-04 23:01:42 +08:00
type StructOfTag struct {
field1 string `json:"field-1"`
field2 string `json:"-"`
field3 int `json:",string"`
2016-12-01 00:56:25 +08:00
}
2016-12-04 23:01:42 +08:00
func Test_reflect_struct_tag_field(t *testing.T) {
2016-12-05 10:49:33 +08:00
err := jsoniter.Unmarshal(`{"field-1": "hello", "field2": "", "field3": "100"}`, &struct_)
2016-12-04 23:01:42 +08:00
if struct_.field1 != "hello" {
2016-12-05 10:49:33 +08:00
fmt.Println(err)
2016-12-04 23:01:42 +08:00
t.Fatal(struct_.field1)
2016-12-01 00:56:25 +08:00
}
2016-12-04 23:01:42 +08:00
if struct_.field2 != "world" {
2016-12-05 10:49:33 +08:00
fmt.Println(err)
2016-12-04 23:01:42 +08:00
t.Fatal(struct_.field2)
}
if struct_.field3 != 100 {
2016-12-05 10:49:33 +08:00
fmt.Println(err)
2016-12-04 23:01:42 +08:00
t.Fatal(struct_.field3)
2016-12-01 00:56:25 +08:00
}
}
```
2016-12-04 23:01:42 +08:00
# StAX style api
2016-12-01 23:25:29 +08:00
2016-12-05 13:31:59 +08:00
When you need the maximum performance, the pull style api allows you to control every bit of parsing process. You
can bind value to object without reflection, or you can calculate the sum of array on the fly without intermediate objects.
2016-12-04 23:01:42 +08:00
Array
2016-12-01 23:25:29 +08:00
```
2016-12-04 23:18:17 +08:00
iter := jsoniter.ParseString(`[1,2,3]`)
2016-12-04 23:01:42 +08:00
for iter.ReadArray() {
iter.ReadUint64()
2016-12-01 23:25:29 +08:00
}
```
2016-12-04 23:01:42 +08:00
Object
2016-12-01 23:25:29 +08:00
```
2016-12-04 23:01:42 +08:00
type TestObj struct {
Field1 string
Field2 uint64
2016-12-01 23:25:29 +08:00
}
```
```
2016-12-04 23:18:17 +08:00
iter := jsoniter.ParseString(`{"field1": "1", "field2": 2}`)
2016-12-04 23:01:42 +08:00
obj := TestObj{}
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field {
case "field1":
obj.Field1 = iter.ReadString()
case "field2":
obj.Field2 = iter.ReadUint64()
default:
iter.ReportError("bind object", "unexpected field")
}
2016-12-01 23:25:29 +08:00
}
```
2016-12-04 23:01:42 +08:00
Skip
2016-12-01 23:25:29 +08:00
```
2016-12-04 23:18:17 +08:00
iter := jsoniter.ParseString(`[ {"a" : [{"b": "c"}], "d": 102 }, "b"]`)
2016-12-04 23:01:42 +08:00
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
2016-12-01 23:25:29 +08:00
}
2016-12-05 13:31:59 +08:00
```
# Customization
Of course, you can use the low level pull api to do anything you like. But most of the time,
reflection based api is fast enough. How to control the parsing process when we are using the reflection api?
json.Unmarshaller is not flexible enough. Jsoniter provides much better customizability.
```
func Test_customize_type_decoder(t *testing.T) {
RegisterTypeDecoder("time.Time", func(ptr unsafe.Pointer, iter *Iterator) {
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.UTC)
if err != nil {
iter.Error = err
return
}
*((*time.Time)(ptr)) = t
})
defer ClearDecoders()
val := time.Time{}
err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
if err != nil {
t.Fatal(err)
}
year, month, day := val.Date()
if year != 2016 || month != 12 || day != 5 {
t.Fatal(val)
}
}
```
there is no way to add json.Unmarshaller to time.Time as the type is not defined by you. Using jsoniter, we can.
```
type Tom struct {
field1 string
}
func Test_customize_field_decoder(t *testing.T) {
RegisterFieldDecoder("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
})
defer ClearDecoders()
tom := Tom{}
err := Unmarshal([]byte(`{"field1": 100}`), &tom)
if err != nil {
t.Fatal(err)
}
}
```
It is very common the input json has certain fields massed up. We want string, but it is int, etc. The old way is to
define a struct of exact type like the json. Then we convert from one struct to a new struct. It is just too much work.
Using jsoniter you can tweak the field conversion.