diff --git a/encoding/gjson/gjson.go b/encoding/gjson/gjson.go index f29351bb9..1087422a6 100644 --- a/encoding/gjson/gjson.go +++ b/encoding/gjson/gjson.go @@ -86,6 +86,7 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { } case []interface{}: + // A string key. if !gstr.IsNumeric(array[i]) { if i == length-1 { *pointer = map[string]interface{}{array[i]: value} @@ -97,23 +98,24 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { } continue } - - valn, err := strconv.Atoi(array[i]) + // Numeric index. + valueNum, err := strconv.Atoi(array[i]) if err != nil { return err } - // Leaf node. + if i == length-1 { - if len((*pointer).([]interface{})) > valn { + // Leaf node. + if len((*pointer).([]interface{})) > valueNum { if removed && value == nil { // Deleting element. if pparent == nil { - *pointer = append((*pointer).([]interface{})[:valn], (*pointer).([]interface{})[valn+1:]...) + *pointer = append((*pointer).([]interface{})[:valueNum], (*pointer).([]interface{})[valueNum+1:]...) } else { - j.setPointerWithValue(pparent, array[i-1], append((*pointer).([]interface{})[:valn], (*pointer).([]interface{})[valn+1:]...)) + j.setPointerWithValue(pparent, array[i-1], append((*pointer).([]interface{})[:valueNum], (*pointer).([]interface{})[valueNum+1:]...)) } } else { - (*pointer).([]interface{})[valn] = value + (*pointer).([]interface{})[valueNum] = value } } else { if removed && value == nil { @@ -124,19 +126,33 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { j.setPointerWithValue(pointer, array[i], value) } else { // It is not the root node. - s := make([]interface{}, valn+1) + s := make([]interface{}, valueNum+1) copy(s, (*pointer).([]interface{})) - s[valn] = value + s[valueNum] = value j.setPointerWithValue(pparent, array[i-1], s) } } } else { + // Branch node. if gstr.IsNumeric(array[i+1]) { n, _ := strconv.Atoi(array[i+1]) - if len((*pointer).([]interface{})) > valn { - (*pointer).([]interface{})[valn] = make([]interface{}, n+1) - pparent = pointer - pointer = &(*pointer).([]interface{})[valn] + pSlice := (*pointer).([]interface{}) + if len(pSlice) > valueNum { + item := pSlice[valueNum] + if s, ok := item.([]interface{}); ok { + for i := 0; i < n-len(s); i++ { + s = append(s, nil) + } + pparent = pointer + pointer = &pSlice[valueNum] + } else { + if removed && value == nil { + goto done + } + var v interface{} = make([]interface{}, n+1) + pparent = j.setPointerWithValue(pointer, array[i], v) + pointer = &v + } } else { if removed && value == nil { goto done @@ -146,14 +162,26 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { pointer = &v } } else { - v := (*pointer).([]interface{}) - if len(v) > valn { + pSlice := (*pointer).([]interface{}) + if len(pSlice) > valueNum { pparent = pointer - pointer = &(*pointer).([]interface{})[valn] + pointer = &(*pointer).([]interface{})[valueNum] } else { - var v interface{} = make(map[string]interface{}) - pparent = j.setPointerWithValue(pointer, array[i], v) - pointer = &v + s := make([]interface{}, valueNum+1) + copy(s, pSlice) + s[valueNum] = make(map[string]interface{}) + if pparent != nil { + // i > 0 + j.setPointerWithValue(pparent, array[i-1], s) + pparent = pointer + pointer = &s[valueNum] + } else { + // i = 0 + var v interface{} = s + *pointer = v + pparent = pointer + pointer = &s[valueNum] + } } } } @@ -177,19 +205,24 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { pparent = pointer } } else { - var v interface{} = make(map[string]interface{}) + var v1, v2 interface{} if i == length-1 { - v = map[string]interface{}{ + v1 = map[string]interface{}{ array[i]: value, } + } else { + v1 = map[string]interface{}{ + array[i]: nil, + } } if pparent != nil { - pparent = j.setPointerWithValue(pparent, array[i-1], v) + pparent = j.setPointerWithValue(pparent, array[i-1], v1) } else { - *pointer = v + *pointer = v1 pparent = pointer } - pointer = &v + v2 = v1.(map[string]interface{})[array[i]] + pointer = &v2 } } } diff --git a/encoding/gjson/gjson_z_unit_basic_test.go b/encoding/gjson/gjson_z_unit_basic_test.go index 2de9ebf5a..6269c94ff 100644 --- a/encoding/gjson/gjson_z_unit_basic_test.go +++ b/encoding/gjson/gjson_z_unit_basic_test.go @@ -419,7 +419,7 @@ func Test_Basic(t *testing.T) { j = gjson.New(`[1,2,3]`) err = j.Remove("0.3") t.Assert(err, nil) - t.Assert(len(j.Get("0").([]interface{})), 3) + t.Assert(j.Get("0"), 1) j = gjson.New(`[1,2,3]`) err = j.Remove("0.a") diff --git a/encoding/gjson/gjson_z_unit_internal_test.go b/encoding/gjson/gjson_z_unit_internal_test.go new file mode 100644 index 000000000..1520437a6 --- /dev/null +++ b/encoding/gjson/gjson_z_unit_internal_test.go @@ -0,0 +1,17 @@ +// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gjson + +//func Test_Load_YAML3(t *testing.T) { +// data := []byte(` +//bb = """ +// dig := dig; END;""" +//`) +// gtest.C(t, func(t *gtest.T) { +// t.Assert(checkDataType(data), "toml") +// }) +//} diff --git a/encoding/gjson/gjson_z_unit_set_test.go b/encoding/gjson/gjson_z_unit_set_test.go index 2ed5eae15..353a0e214 100644 --- a/encoding/gjson/gjson_z_unit_set_test.go +++ b/encoding/gjson/gjson_z_unit_set_test.go @@ -8,6 +8,9 @@ package gjson_test import ( "bytes" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/test/gtest" + "github.com/gogf/gf/text/gstr" "testing" "github.com/gogf/gf/encoding/gjson" @@ -31,17 +34,13 @@ func Test_Set1(t *testing.T) { } func Test_Set2(t *testing.T) { - e := []byte(`[[null,1]]`) - p := gjson.New([]string{"a"}) - p.Set("0.1", 1) - if c, err := p.ToJson(); err == nil { - - if bytes.Compare(c, e) != 0 { - t.Error("expect:", string(e)) - } - } else { - t.Error(err) - } + gtest.C(t, func(t *gtest.T) { + e := `[[null,1]]` + p := gjson.New([]string{"a"}) + p.Set("0.1", 1) + s := p.MustToJsonString() + t.Assert(s, e) + }) } func Test_Set3(t *testing.T) { @@ -51,7 +50,6 @@ func Test_Set3(t *testing.T) { "k1": "v1", }) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -227,3 +225,107 @@ func Test_Set14(t *testing.T) { t.Error(err) } } + +func Test_Set15(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + + t.Assert(j.Set("root.0.k1", "v1"), nil) + t.Assert(j.Set("root.1.k2", "v2"), nil) + t.Assert(j.Set("k", "v"), nil) + + s, err := j.ToJsonString() + t.Assert(err, nil) + t.Assert( + gstr.Contains(s, `"root":[{"k1":"v1"},{"k2":"v2"}`) || + gstr.Contains(s, `"root":[{"k2":"v2"},{"k1":"v1"}`), + true, + ) + t.Assert( + gstr.Contains(s, `{"k":"v"`) || + gstr.Contains(s, `"k":"v"}`), + true, + ) + }) +} + +func Test_Set16(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + + t.Assert(j.Set("processors.0.set.0value", "1"), nil) + t.Assert(j.Set("processors.0.set.0field", "2"), nil) + t.Assert(j.Set("description", "3"), nil) + + s, err := j.ToJsonString() + t.Assert(err, nil) + t.Assert( + gstr.Contains(s, `"processors":[{"set":{"0field":"2","0value":"1"}}]`) || + gstr.Contains(s, `"processors":[{"set":{"0value":"1","0field":"2"}}]`), + true, + ) + t.Assert( + gstr.Contains(s, `{"description":"3"`) || gstr.Contains(s, `"description":"3"}`), + true, + ) + }) +} + +func Test_Set17(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + + t.Assert(j.Set("0.k1", "v1"), nil) + t.Assert(j.Set("1.k2", "v2"), nil) + // overwrite the previous slice. + t.Assert(j.Set("k", "v"), nil) + + s, err := j.ToJsonString() + t.Assert(err, nil) + t.Assert(s, `{"k":"v"}`) + }) +} + +func Test_Set18(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + + t.Assert(j.Set("0.1.k1", "v1"), nil) + t.Assert(j.Set("0.2.k2", "v2"), nil) + s, err := j.ToJsonString() + t.Assert(err, nil) + t.Assert(s, `[[null,{"k1":"v1"},{"k2":"v2"}]]`) + }) +} + +func Test_Set19(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + + t.Assert(j.Set("0.1.1.k1", "v1"), nil) + t.Assert(j.Set("0.2.1.k2", "v2"), nil) + s, err := j.ToJsonString() + t.Assert(err, nil) + t.Assert(s, `[[null,[null,{"k1":"v1"}],[null,{"k2":"v2"}]]]`) + }) +} + +func Test_Set20(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + + t.Assert(j.Set("k1", "v1"), nil) + t.Assert(j.Set("k2", g.Slice{1, 2, 3}), nil) + t.Assert(j.Set("k2.1", 20), nil) + t.Assert(j.Set("k2.2", g.Map{"k3": "v3"}), nil) + s, err := j.ToJsonString() + t.Assert(err, nil) + t.Assert(gstr.InArray( + g.SliceStr{ + `{"k1":"v1","k2":[1,20,{"k3":"v3"}]}`, + `{"k2":[1,20,{"k3":"v3"}],"k1":"v1"}`, + }, + s, + ), true) + }) +}