diff --git a/g/encoding/gjson/gjson.go b/g/encoding/gjson/gjson.go index bdacc4578..da2f1e226 100644 --- a/g/encoding/gjson/gjson.go +++ b/g/encoding/gjson/gjson.go @@ -4,9 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -// Package gjson provides flexible and useful API for JSON/XML/YAML/TOML content handling. -// -// JSON/XML/YAML/TOML数据格式处理。 +// Package gjson provides convenient API for JSON/XML/YAML/TOML data handling. package gjson import ( @@ -19,7 +17,6 @@ import ( "github.com/gogf/gf/g/encoding/gyaml" "github.com/gogf/gf/g/internal/rwmutex" "github.com/gogf/gf/g/os/gfcache" - "github.com/gogf/gf/g/os/gfile" "github.com/gogf/gf/g/text/gregex" "github.com/gogf/gf/g/text/gstr" "github.com/gogf/gf/g/util/gconv" @@ -30,18 +27,24 @@ import ( ) const ( - gDEFAULT_SPLIT_CHAR = '.' // 默认层级分隔符号 + // Separator char for hierarchical data access. + gDEFAULT_SPLIT_CHAR = '.' ) -// json解析结果存放数组 +// The customized JSON struct. type Json struct { mu *rwmutex.RWMutex - p *interface{} // 注意这是一个指针 - c byte // 层级分隔符,默认为"." - vc bool // 层级检索是否执行分隔符冲突检测(默认为false,检测会比较影响检索效率) + p *interface{} // Pointer for hierarchical data access, it's the root of data in default. + c byte // Char separator('.' in default). + vc bool // Violence Check(false in default), which is used to access data + // when the hierarchical data key contains separator char. } -// 将变量转换为Json对象进行处理,该变量至少应当是一个map或者slice,否者转换没有意义 +// New creates a Json object with any variable type of , +// but should be a map or slice for data access reason, +// or it will make no sense. +// The param specifies whether using this Json object +// in un-concurrent-safe context, which is false in default. func New(data interface{}, unsafe...bool) *Json { j := (*Json)(nil) switch data.(type) { @@ -75,7 +78,7 @@ func New(data interface{}, unsafe...bool) *Json { return j } -// 创建一个非并发安全的Json对象 +// NewUnsafe creates a un-concurrent-safe Json object. func NewUnsafe(data...interface{}) *Json { if len(data) > 0 { return New(data[0], true) @@ -83,17 +86,17 @@ func NewUnsafe(data...interface{}) *Json { return New(nil, true) } -// 识别当前给定内容是否为JSON格式 +// Valid checks whether is a valid JSON data type. func Valid(data interface{}) bool { return json.Valid(gconv.Bytes(data)) } -// 编码go变量为json字符串,并返回json字符串指针 +// Encode encodes to JSON data type of bytes. func Encode(value interface{}) ([]byte, error) { return json.Marshal(value) } -// 解码字符串/[]byte为interface{}变量 +// Decode decodes (string/[]byte) to golang variable. func Decode(data interface{}) (interface{}, error) { var value interface{} if err := DecodeTo(gconv.Bytes(data), &value); err != nil { @@ -103,58 +106,63 @@ func Decode(data interface{}) (interface{}, error) { } } -// 解析json字符串/[]byte为go变量,注意第二个参数为指针(任意结构的变量) +// Decode decodes (string/[]byte) to specified golang variable . +// The should be a pointer type. func DecodeTo(data interface{}, v interface{}) error { decoder := json.NewDecoder(bytes.NewReader(gconv.Bytes(data))) decoder.UseNumber() return decoder.Decode(v) } -// 解析json字符串为gjson.Json对象,并返回操作对象指针 -func DecodeToJson(data interface{}) (*Json, error) { +// DecodeToJson codes (string/[]byte) to a Json object. +func DecodeToJson(data interface{}, unsafe...bool) (*Json, error) { if v, err := Decode(gconv.Bytes(data)); err != nil { return nil, err } else { - return New(v), nil + return New(v, unsafe...), nil } } -// 支持多种配置文件类型转换为json格式内容并解析为gjson.Json对象 -func Load(path string) (*Json, error) { - return LoadContent(gfcache.GetBinContents(path), gfile.Ext(path)) +// Load loads content from specified file , +// and creates a Json object from its content. +func Load(path string, unsafe...bool) (*Json, error) { + return LoadContent(gfcache.GetBinContents(path), unsafe...) } -// 支持的配置文件格式:xml, json, yaml/yml, toml, -// 默认为自动识别,当无法检测成功时使用json解析。 -func LoadContent(data interface{}, dataType...string) (*Json, error) { +// LoadContent creates a Json object from given content, +// it checks the data type of automatically, +// supporting JSON, XML, YAML and TOML types of data. +func LoadContent(data interface{}, unsafe...bool) (*Json, error) { var err error var result interface{} b := gconv.Bytes(data) t := "json" - if len(dataType) > 0 { - t = dataType[0] + // auto check data type + if json.Valid(b) { + t = "json" + } else if gregex.IsMatch(`^<.+>.*$`, b) { + t = "xml" + } else if gregex.IsMatch(`^[\s\t]*\w+\s*:\s*.+`, b) || gregex.IsMatch(`\n[\s\t]*\w+\s*:\s*.+`, b) { + t = "yml" + } else if gregex.IsMatch(`^[\s\t]*\w+\s*=\s*.+`, b) || gregex.IsMatch(`\n[\s\t]*\w+\s*=\s*.+`, b) { + t = "toml" } else { - if json.Valid(b) { - t = "json" - } else if gregex.IsMatch(`<.+>.*`, b) { - t = "xml" - } else if gregex.IsMatch(`\n[\s\t]*\w+\s*:\s*.+`, b) { - t = "yml" - } else if gregex.IsMatch(`\n[\s\t]*\w+\s*=\s*.+`, b) { - t = "toml" - } + return nil, errors.New("unsupported data type") } - // 其他数据格式解析 + // convert to json type data switch t { case "json", ".json": // ok case "xml", ".xml": + // TODO UseNumber b, err = gxml.ToJson(b) case "yml", "yaml", ".yml", ".yaml": + // TODO UseNumber b, err = gyaml.ToJson(b) case "toml", ".toml": + // TODO UseNumber b, err = gtoml.ToJson(b) default: @@ -174,26 +182,26 @@ func LoadContent(data interface{}, dataType...string) (*Json, error) { return nil, fmt.Errorf(`json decoding failed for content: %s`, string(b)) } } - return New(result), nil + return New(result, unsafe...), nil } -// 设置自定义的层级分隔符号 +// SetSplitChar sets the separator char for hierarchical data access. func (j *Json) SetSplitChar(char byte) { j.mu.Lock() j.c = char j.mu.Unlock() } -// 设置是否执行层级冲突检查,当键名中存在层级符号时需要开启该特性,默认为关闭。 -// 开启比较耗性能,也不建议允许键名中存在分隔符,最好在应用端避免这种情况。 -func (j *Json) SetViolenceCheck(check bool) { +// SetViolenceCheck enables/disables violence check for hierarchical data access. +func (j *Json) SetViolenceCheck(enabled bool) { j.mu.Lock() - j.vc = check + j.vc = enabled j.mu.Unlock() } -// 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil -// 注意第二个参数需要给的是**变量地址** +// GetToVar gets the value by specified , +// and converts it to specified golang variable . +// The should be a pointer type. func (j *Json) GetToVar(pattern string, v interface{}) error { r := j.Get(pattern) if r != nil { @@ -208,19 +216,18 @@ func (j *Json) GetToVar(pattern string, v interface{}) error { return nil } -// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换 -// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil +// GetMap gets the value by specified , +// and converts it to map[string]interface{}. func (j *Json) GetMap(pattern string) map[string]interface{} { result := j.Get(pattern) if result != nil { - if r, ok := result.(map[string]interface{}); ok { - return r - } + return gconv.Map(result) } return nil } -// 将检索值转换为Json对象指针返回。 +// GetJson gets the value by specified , +// and converts it to a Json object. func (j *Json) GetJson(pattern string) *Json { result := j.Get(pattern) if result != nil { @@ -229,7 +236,8 @@ func (j *Json) GetJson(pattern string) *Json { return nil } -// 将检索值转换为Json对象指针数组返回。 +// GetJsons gets the value by specified , +// and converts it to a slice of Json object. func (j *Json) GetJsons(pattern string) []*Json { array := j.GetArray(pattern) if len(array) > 0 { @@ -242,21 +250,25 @@ func (j *Json) GetJsons(pattern string) []*Json { return nil } -// 获得一个数组[]interface{},方便操作,不需要自己做类型转换。 +// GetArray gets the value by specified , +// and converts it to a slice of []interface{}. func (j *Json) GetArray(pattern string) []interface{} { return gconv.Interfaces(j.Get(pattern)) } -// 返回指定json中的string +// GetString gets the value by specified , +// and converts it to string. func (j *Json) GetString(pattern string) string { return gconv.String(j.Get(pattern)) } -// 返回指定json中的strings(转换为[]string数组) +// GetStrings gets the value by specified , +// and converts it to a slice of []string. func (j *Json) GetStrings(pattern string) []string { return gconv.Strings(j.Get(pattern)) } +// See GetArray. func (j *Json) GetInterfaces(pattern string) []interface{} { return gconv.Interfaces(j.Get(pattern)) } @@ -269,7 +281,10 @@ func (j *Json) GetTimeDuration(pattern string) time.Duration { return gconv.TimeDuration(j.Get(pattern)) } -// 返回指定json中的bool(false:"", 0, false, off) +// GetBool gets the value by specified , +// and converts it to bool. +// It returns false when value is: "", 0, false, off, nil; +// or returns true instead. func (j *Json) GetBool(pattern string) bool { return gconv.Bool(j.Get(pattern)) } @@ -330,25 +345,29 @@ func (j *Json) GetFloats(pattern string) []float64 { return gconv.Floats(j.Get(pattern)) } -// 将指定变量转换为struct对象(对象属性赋值) +// GetToStruct gets the value by specified , +// and converts it to specified object . +// The should be the pointer to an object. func (j *Json) GetToStruct(pattern string, objPointer interface{}) error { return gconv.Struct(j.Get(pattern), objPointer) } -// 动态设置层级变量 +// Set sets value with specified . +// It supports hierarchical data access by char separator, which is '.' in default. func (j *Json) Set(pattern string, value interface{}) error { return j.setValue(pattern, value, false) } -// 动态删除层级变量 +// Remove deletes value with specified . +// It supports hierarchical data access by char separator, which is '.' in default. func (j *Json) Remove(pattern string) error { return j.setValue(pattern, nil, true) } -// 根据pattern查找并设置数据 -// 注意: -// 1、写入的value为nil且removed为true时,表示删除; -// 2、里面的层级处理比较复杂,逻辑较复杂的地方在于层级检索及节点创建,叶子赋值; +// Set by . +// Notice: +// 1. If value is nil and removed is true, means deleting this value; +// 2. It's quite complicated in hierarchical data search, node creating and data assignment; func (j *Json) setValue(pattern string, value interface{}, removed bool) error { array := strings.Split(pattern, string(j.c)) length := len(array) @@ -367,144 +386,144 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { defer j.mu.Unlock() for i:= 0; i < length; i++ { switch (*pointer).(type) { - case map[string]interface{}: - if i == length - 1 { - if removed && value == nil { - // 删除map元素 - delete((*pointer).(map[string]interface{}), array[i]) - } else { - (*pointer).(map[string]interface{})[array[i]] = value - } - } else { - // 当键名不存在的情况这里会进行处理 - if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok { - if removed && value == nil { - goto done - } - // 创建新节点 - if gstr.IsNumeric(array[i + 1]) { - // 创建array节点 - n, _ := strconv.Atoi(array[i + 1]) - var v interface{} = make([]interface{}, n + 1) - pparent = j.setPointerWithValue(pointer, array[i], v) - pointer = &v - } else { - // 创建map节点 - var v interface{} = make(map[string]interface{}) - pparent = j.setPointerWithValue(pointer, array[i], v) - pointer = &v - } - } else { - pparent = pointer - pointer = &v - } - } - - case []interface{}: - // 键名与当前指针类型不符合,需要执行**覆盖操作** - if !gstr.IsNumeric(array[i]) { + case map[string]interface{}: if i == length - 1 { - *pointer = map[string]interface{}{ array[i] : value } + if removed && value == nil { + // 删除map元素 + delete((*pointer).(map[string]interface{}), array[i]) + } else { + (*pointer).(map[string]interface{})[array[i]] = value + } } else { - var v interface{} = make(map[string]interface{}) - *pointer = v - pparent = pointer - pointer = &v + // 当键名不存在的情况这里会进行处理 + if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok { + if removed && value == nil { + goto done + } + // 创建新节点 + if gstr.IsNumeric(array[i + 1]) { + // 创建array节点 + n, _ := strconv.Atoi(array[i + 1]) + var v interface{} = make([]interface{}, n + 1) + pparent = j.setPointerWithValue(pointer, array[i], v) + pointer = &v + } else { + // 创建map节点 + var v interface{} = make(map[string]interface{}) + pparent = j.setPointerWithValue(pointer, array[i], v) + pointer = &v + } + } else { + pparent = pointer + pointer = &v + } } - continue - } - valn, err := strconv.Atoi(array[i]) - if err != nil { - return err - } - // 叶子节点 - if i == length - 1 { - if len((*pointer).([]interface{})) > valn { - if removed && value == nil { - // 删除数据元素 - j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...)) + case []interface{}: + // 键名与当前指针类型不符合,需要执行**覆盖操作** + if !gstr.IsNumeric(array[i]) { + if i == length - 1 { + *pointer = map[string]interface{}{ array[i] : value } } else { - (*pointer).([]interface{})[valn] = value - } - } else { - if removed && value == nil { - goto done - } - if pparent == nil { - // 表示根节点 - j.setPointerWithValue(pointer, array[i], value) - } else { - // 非根节点 - s := make([]interface{}, valn + 1) - copy(s, (*pointer).([]interface{})) - s[valn] = value - j.setPointerWithValue(pparent, array[i - 1], s) + var v interface{} = make(map[string]interface{}) + *pointer = v + pparent = pointer + pointer = &v } + continue } - } else { - if gstr.IsNumeric(array[i + 1]) { - n, _ := strconv.Atoi(array[i + 1]) + + valn, err := strconv.Atoi(array[i]) + if err != nil { + return err + } + // 叶子节点 + if i == length - 1 { if len((*pointer).([]interface{})) > valn { - (*pointer).([]interface{})[valn] = make([]interface{}, n + 1) - pparent = pointer - pointer = &(*pointer).([]interface{})[valn] + if removed && value == nil { + // 删除数据元素 + j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...)) + } else { + (*pointer).([]interface{})[valn] = value + } } else { if removed && value == nil { goto done } - var v interface{} = make([]interface{}, n + 1) + if pparent == nil { + // 表示根节点 + j.setPointerWithValue(pointer, array[i], value) + } else { + // 非根节点 + s := make([]interface{}, valn + 1) + copy(s, (*pointer).([]interface{})) + s[valn] = value + j.setPointerWithValue(pparent, array[i - 1], s) + } + } + } else { + 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] + } else { + if removed && value == nil { + goto done + } + var v interface{} = make([]interface{}, n + 1) + pparent = j.setPointerWithValue(pointer, array[i], v) + pointer = &v + } + } else { + var v interface{} = make(map[string]interface{}) pparent = j.setPointerWithValue(pointer, array[i], v) pointer = &v } - } else { - var v interface{} = make(map[string]interface{}) - pparent = j.setPointerWithValue(pointer, array[i], v) - pointer = &v } - } // 如果当前指针指向的变量不是引用类型的, // 那么修改变量必须通过父级进行修改,即 pparent - default: - if removed && value == nil { - goto done - } - if gstr.IsNumeric(array[i]) { - n, _ := strconv.Atoi(array[i]) - s := make([]interface{}, n + 1) - if i == length - 1 { - s[n] = value + default: + if removed && value == nil { + goto done } - if pparent != nil { - pparent = j.setPointerWithValue(pparent, array[i - 1], s) - } else { - *pointer = s - pparent = pointer - } - } else { - var v interface{} = make(map[string]interface{}) - if i == length - 1 { - v = map[string]interface{}{ - array[i] : value, + if gstr.IsNumeric(array[i]) { + n, _ := strconv.Atoi(array[i]) + s := make([]interface{}, n + 1) + if i == length - 1 { + s[n] = value + } + if pparent != nil { + pparent = j.setPointerWithValue(pparent, array[i - 1], s) + } else { + *pointer = s + pparent = pointer } - } - if pparent != nil { - pparent = j.setPointerWithValue(pparent, array[i - 1], v) } else { - *pointer = v - pparent = pointer + var v interface{} = make(map[string]interface{}) + if i == length - 1 { + v = map[string]interface{}{ + array[i] : value, + } + } + if pparent != nil { + pparent = j.setPointerWithValue(pparent, array[i - 1], v) + } else { + *pointer = v + pparent = pointer + } + pointer = &v } - pointer = &v - } - } } done: return nil } -// 数据结构转换,map参数必须转换为map[string]interface{},数组参数必须转换为[]interface{} +// Convert to map[string]interface{} or []interface{}, +// which can be supported for hierarchical data access. func (j *Json) convertValue(value interface{}) interface{} { switch value.(type) { case map[string]interface{}: @@ -524,7 +543,7 @@ func (j *Json) convertValue(value interface{}) interface{} { case reflect.Map: return gconv.Map(value) case reflect.Struct: return gconv.Map(value) default: - // 最后使用JSON编解码 + // Use json decode/encode at last. b, _ := Encode(value) v, _ := Decode(b) return v @@ -532,8 +551,8 @@ func (j *Json) convertValue(value interface{}) interface{} { } } -// 用于Set方法中,对指针指向的内存地址进行赋值 -// 返回修改后的父级指针 +// Set : to , the may be a map key or slice index. +// It returns the pointer to the new value set. func (j *Json) setPointerWithValue(pointer *interface{}, key string, value interface{}) *interface{} { switch (*pointer).(type) { case map[string]interface{}: @@ -557,9 +576,12 @@ func (j *Json) setPointerWithValue(pointer *interface{}, key string, value inter return pointer } -// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"; 当pattern为空时,表示获取所有数据; -// 返回的结果类型的interface{},因此需要自己做类型转换; -// 如果找不到对应节点的数据,返回nil; +// Get returns value by specified . +// It returns all values of current Json object, if is empty or not specified. +// It returns nil if no value found by . +// +// We can also access slice item by its index number in , +// eg: "items.name.first", "list.10". func (j *Json) Get(pattern...string) interface{} { j.mu.RLock() defer j.mu.RUnlock() @@ -580,13 +602,14 @@ func (j *Json) Get(pattern...string) interface{} { return nil } -// 判断锁给定pattern是否数据存在 +// Contains checks whether the value by specified exist. func (j *Json) Contains(pattern...string) bool { return j.Get(pattern...) != nil } -// 计算指定pattern的元素长度(pattern对应数据类型为map/slice时有效)。 -// 当pattern对应的数据类型非map/slice时,返回-1。 +// Len returns the length/size of the value by specified . +// The target value by should be type of slice or map. +// It returns -1 if the target value is not found, or its type is invalid. func (j *Json) Len(pattern string) int { p := j.getPointerByPattern(pattern) if p != nil { @@ -602,7 +625,8 @@ func (j *Json) Len(pattern string) int { return -1 } -// 指定pattern追加元素 +// Append appends value to the value by specified . +// The target value by should be type of slice. func (j *Json) Append(pattern string, value interface{}) error { p := j.getPointerByPattern(pattern) if p == nil { @@ -615,7 +639,7 @@ func (j *Json) Append(pattern string, value interface{}) error { return fmt.Errorf("invalid variable type of %s", pattern) } -// 根据pattern获取对应元素项的指针 +// Get a pointer to the value by specified . func (j *Json) getPointerByPattern(pattern string) *interface{} { if j.vc { return j.getPointerByPatternWithViolenceCheck(pattern) @@ -624,18 +648,7 @@ func (j *Json) getPointerByPattern(pattern string) *interface{} { } } -// 根据pattern层级查找**变量指针**, 执行冲突检测。 -// 检索方式:例如检索 a.a.a ,值为1 -// 1. 检索 a.a.a.a 是否存在对应map的键名; -// 2. 检索 a.a.a 是否存在对应map的键名; -// 3. 检索 a.a 是否存在对应map的键名; -// 4. 检索 a 是否存在对应map的键名,如果检索出这是一个map,假如为变量m1; -// 5. 在m1中检索 a.a.a 否存在对应map的键名; -// 6. 在m1中检索 a.a 否存在对应map的键名; -// 7. 在m1中检索 a 否存在对应map的键名,如果检索出这是一个map,假如为变量m2; -// 8. 在m2中检索 a.a 否存在对应map的键名; -// 9. 在m2中检索 a 否存在对应map的键名,检索到有值,值为1; -// 这样检索的复杂度很高,主要是为了避免键名中存在分隔符号(默认为".")的情况,避免歧义。 +// Get a pointer to the value of specified with violence check. func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} { if !j.vc { return j.getPointerByPatternWithoutViolenceCheck(pattern) @@ -661,7 +674,7 @@ func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} pointer = r } } else { - // 查找下一个分割符号的索引位置 + // Get the position for next separator char. index = strings.LastIndexByte(pattern[start:index], j.c) if index != -1 && length > 0 { index += length + 1 @@ -674,7 +687,7 @@ func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} return nil } -// 层级检索,内部不执行分隔符冲突检查,检索效率会有所提高,但是冲突需要开发者自己根据自定义的分隔符来进行解决 +// Get a pointer to the value of specified , with no violence check. func (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *interface{} { if j.vc { return j.getPointerByPatternWithViolenceCheck(pattern) @@ -698,8 +711,8 @@ func (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *interfac return nil } -// 判断给定的key在当前的pointer下是否有值,并返回对应的pointer, -// 注意这里返回的指针都是临时变量的内存地址 +// Check whether there's value by in specified . +// It returns a pointer to the value. func (j *Json) checkPatternByPointer(key string, pointer *interface{}) *interface{} { switch (*pointer).(type) { case map[string]interface{}: @@ -717,7 +730,8 @@ func (j *Json) checkPatternByPointer(key string, pointer *interface{}) *interfac return nil } -// 转换为map[string]interface{}类型,如果转换失败,返回nil +// ToMap converts current Json object to map[string]interface{}. +// It returns nil if fails. func (j *Json) ToMap() map[string]interface{} { j.mu.RLock() defer j.mu.RUnlock() @@ -729,15 +743,16 @@ func (j *Json) ToMap() map[string]interface{} { } } -// 转换为[]interface{}类型,如果转换失败,返回nil +// ToArray converts current Json object to []interface{}. +// It returns nil if fails. func (j *Json) ToArray() []interface{} { j.mu.RLock() defer j.mu.RUnlock() switch (*(j.p)).(type) { - case []interface{}: - return (*(j.p)).([]interface{}) - default: - return nil + case []interface{}: + return (*(j.p)).([]interface{}) + default: + return nil } } @@ -803,14 +818,15 @@ func (j *Json) ToTomlString() (string, error) { return string(b), e } -// 转换为指定的struct对象 -func (j *Json) ToStruct(o interface{}) error { +// ToStruct converts current Json object to specified object. +// The should be a pointer type. +func (j *Json) ToStruct(objPointer interface{}) error { j.mu.RLock() defer j.mu.RUnlock() - return gconv.Struct(*(j.p), o) + return gconv.Struct(*(j.p), objPointer) } -// 打印Json对象 +// Dump prints current Json object with more manually readable. func (j *Json) Dump() error { j.mu.RLock() defer j.mu.RUnlock() diff --git a/g/encoding/gjson/gjson_unit_load_test.go b/g/encoding/gjson/gjson_unit_load_test.go index 40e2cd88a..7c096428e 100644 --- a/g/encoding/gjson/gjson_unit_load_test.go +++ b/g/encoding/gjson/gjson_unit_load_test.go @@ -69,7 +69,7 @@ func Test_Load_XML(t *testing.T) { }) } -func Test_Load_YAML(t *testing.T) { +func Test_Load_YAML1(t *testing.T) { data := []byte(` a: - 1 @@ -104,7 +104,16 @@ m: }) } -func Test_Load_TOML(t *testing.T) { +func Test_Load_YAML2(t *testing.T) { + data := []byte("i : 123456789") + gtest.Case(t, func() { + j, err := gjson.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("i"), "123456789") + }) +} + +func Test_Load_TOML1(t *testing.T) { data := []byte(` a = ["1", "2", "3"] n = "123456789" @@ -136,3 +145,12 @@ n = "123456789" gtest.Assert(j.Get("a.1"), 2) }) } + +func Test_Load_TOML2(t *testing.T) { + data := []byte("i=123456789") + gtest.Case(t, func() { + j, err := gjson.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("i"), "123456789") + }) +} diff --git a/g/encoding/gjson/gjson_unit_set_test.go b/g/encoding/gjson/gjson_unit_set_test.go index 666b8842a..caac7f7ea 100644 --- a/g/encoding/gjson/gjson_unit_set_test.go +++ b/g/encoding/gjson/gjson_unit_set_test.go @@ -172,7 +172,7 @@ func Test_Set10(t *testing.T) { func Test_Set11(t *testing.T) { e := []byte(`{"a":{"b":{}}}`) - p, _ := gjson.LoadContent([]byte(`{"a":{"b":{"c":1}}}`), "json") + p, _ := gjson.LoadContent([]byte(`{"a":{"b":{"c":1}}}`)) p.Remove("a.b.c") if c, err := p.ToJson(); err == nil { diff --git a/g/encoding/gparser/gparser.go b/g/encoding/gparser/gparser.go index 8cc086342..2e388d7ce 100644 --- a/g/encoding/gparser/gparser.go +++ b/g/encoding/gparser/gparser.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://gitee.com/johng/gp. -// Package gparser provides a flexible and easy way for accessing/converting variable and JSON/XML/YAML/TOML contents. +// Package gparser provides convenient API for accessing/converting variable and JSON/XML/YAML/TOML. package gparser import ( @@ -16,13 +16,16 @@ type Parser struct { json *gjson.Json } -// 将变量转换为Parser对象进行处理,该变量至少应当是一个map或者array,否者转换没有意义 -// value可以传递nil, 表示创建一个空的Parser对象 -func New (value interface{}, unsafe...bool) *Parser { +// New creates a Parser object with any variable type of , +// but should be a map or slice for data access reason, +// or it will make no sense. +// The param specifies whether using this Parser object +// in un-concurrent-safe context, which is false in default. +func New(value interface{}, unsafe...bool) *Parser { return &Parser{gjson.New(value, unsafe...)} } -// 非并发安全Parser对象 +// NewUnsafe creates a un-concurrent-safe Parser object. func NewUnsafe (value...interface{}) *Parser { if len(value) > 0 { return &Parser{gjson.New(value[0], false)} @@ -30,57 +33,64 @@ func NewUnsafe (value...interface{}) *Parser { return &Parser{gjson.New(nil, false)} } -func Load (path string) (*Parser, error) { - if j, e := gjson.Load(path); e == nil { +// Load loads content from specified file , +// and creates a Parser object from its content. +func Load (path string, unsafe...bool) (*Parser, error) { + if j, e := gjson.Load(path, unsafe...); e == nil { return &Parser{j}, nil } else { return nil, e } } -// 支持的数据内容格式:json(默认), xml, yaml/yml, toml -func LoadContent (data []byte, dataType...string) (*Parser, error) { - if j, e := gjson.LoadContent(data, dataType...); e == nil { +// LoadContent creates a Parser object from given content, +// it checks the data type of automatically, +// supporting JSON, XML, YAML and TOML types of data. +func LoadContent (data []byte, unsafe...bool) (*Parser, error) { + if j, e := gjson.LoadContent(data, unsafe...); e == nil { return &Parser{j}, nil } else { return nil, e } } -// 设置自定义的层级分隔符号 +// SetSplitChar sets the separator char for hierarchical data access. func (p *Parser) SetSplitChar(char byte) { p.json.SetSplitChar(char) } -// 设置是否执行层级冲突检查,当键名中存在层级符号时需要开启该特性,默认为关闭。 -// 开启比较耗性能,也不建议允许键名中存在分隔符,最好在应用端避免这种情况。 +// SetViolenceCheck enables/disables violence check for hierarchical data access. func (p *Parser) SetViolenceCheck(check bool) { p.json.SetViolenceCheck(check) } -// 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil -// 注意第二个参数需要给的是变量地址 +// GetToVar gets the value by specified , +// and converts it to specified golang variable . +// The should be a pointer type. func (p *Parser) GetToVar(pattern string, v interface{}) error { return p.json.GetToVar(pattern, v) } -// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换 -// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil +// GetMap gets the value by specified , +// and converts it to map[string]interface{}. func (p *Parser) GetMap(pattern string) map[string]interface{} { return p.json.GetMap(pattern) } -// 获得一个数组[]interface{},方便操作,不需要自己做类型转换 -// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil +// GetArray gets the value by specified , +// and converts it to a slice of []interface{}. func (p *Parser) GetArray(pattern string) []interface{} { return p.json.GetArray(pattern) } -// 返回指定json中的string +// GetString gets the value by specified , +// and converts it to string. func (p *Parser) GetString(pattern string) string { return p.json.GetString(pattern) } +// GetStrings gets the value by specified , +// and converts it to a slice of []string. func (p *Parser) GetStrings(pattern string) []string { return p.json.GetStrings(pattern) } @@ -97,7 +107,10 @@ func (p *Parser) GetTimeDuration(pattern string) time.Duration { return p.json.GetTimeDuration(pattern) } -// 返回指定json中的bool(false:"", 0, false, off) +// GetBool gets the value by specified , +// and converts it to bool. +// It returns false when value is: "", 0, false, off, nil; +// or returns true instead. func (p *Parser) GetBool(pattern string) bool { return p.json.GetBool(pattern) } @@ -158,51 +171,60 @@ func (p *Parser) GetFloats(pattern string) []float64 { return p.json.GetFloats(pattern) } -// 将指定变量转换为struct对象(对象属性赋值) +// GetToStruct gets the value by specified , +// and converts it to specified object . +// The should be the pointer to an object. func (p *Parser) GetToStruct(pattern string, objPointer interface{}) error { return p.json.GetToStruct(pattern, objPointer) } -// 根据pattern查找并设置数据 -// 注意:写入的时候"."符号只能表示层级,不能使用带"."符号的键名 +// Set sets value with specified . +// It supports hierarchical data access by char separator, which is '.' in default. func (p *Parser) Set(pattern string, value interface{}) error { return p.json.Set(pattern, value) } -// 计算指定pattern的元素长度(pattern对应数据类型为map[string]interface{}/[]interface{}时有效) +// Len returns the length/size of the value by specified . +// The target value by should be type of slice or map. +// It returns -1 if the target value is not found, or its type is invalid. func (p *Parser) Len(pattern string) int { return p.json.Len(pattern) } -// 指定pattern追加元素 +// Append appends value to the value by specified . +// The target value by should be type of slice. func (p *Parser) Append(pattern string, value interface{}) error { return p.json.Append(pattern, value) } -// 动态删除变量节点 +// Remove deletes value with specified . +// It supports hierarchical data access by char separator, which is '.' in default. func (p *Parser) Remove(pattern string) error { return p.json.Remove(pattern) } -// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"; 当pattern为空时,表示获取所有数据 -// 返回的结果类型的interface{},因此需要自己做类型转换; -// 如果找不到对应节点的数据,返回nil; +// Get returns value by specified . +// It returns all values of current Json object, if is empty or not specified. +// It returns nil if no value found by . +// +// We can also access slice item by its index number in , +// eg: "items.name.first", "list.10". func (p *Parser) Get(pattern...string) interface{} { return p.json.Get(pattern...) } -// 转换为map[string]interface{}类型,如果转换失败,返回nil +// ToMap converts current object values to map[string]interface{}. +// It returns nil if fails. func (p *Parser) ToMap() map[string]interface{} { return p.json.ToMap() } -// 转换为[]interface{}类型,如果转换失败,返回nil +// ToArray converts current object values to []interface{}. +// It returns nil if fails. func (p *Parser) ToArray() []interface{} { return p.json.ToArray() } -/* 以下为数据文件格式转换,支持类型:xml, json, yaml/yml, toml */ - func (p *Parser) ToXml(rootTag...string) ([]byte, error) { return p.json.ToXml(rootTag...) } @@ -227,12 +249,13 @@ func (p *Parser) ToToml() ([]byte, error) { return p.json.ToToml() } -// 打印Json对象 +// Dump prints current Json object with more manually readable. func (p *Parser) Dump() error { return p.json.Dump() } -// 将变量解析为对应的struct对象,注意传递的参数为struct对象指针 +// ToStruct converts current Json object to specified object. +// The should be a pointer type. func (p *Parser) ToStruct(o interface{}) error { return p.json.ToStruct(o) } @@ -261,7 +284,6 @@ func VarToToml(value interface{}) ([]byte, error) { return New(value).ToToml() } -// 将变量解析为对应的struct对象,注意传递的参数为struct对象指针 func VarToStruct(value interface{}, obj interface{}) error { return New(value).ToStruct(obj) } diff --git a/g/encoding/gparser/gparser_unit_basic_test.go b/g/encoding/gparser/gparser_unit_basic_test.go new file mode 100644 index 000000000..bf7067753 --- /dev/null +++ b/g/encoding/gparser/gparser_unit_basic_test.go @@ -0,0 +1,208 @@ +// 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 gparser_test + +import ( + "github.com/gogf/gf/g" + "github.com/gogf/gf/g/encoding/gparser" + "github.com/gogf/gf/g/test/gtest" + "testing" +) + +func Test_New(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + }) +} + +func Test_NewUnsafe(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.NewUnsafe(data) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) +} + +func Test_Encode(t *testing.T) { + value := g.Slice{1, 2, 3} + gtest.Case(t, func() { + b, err := gparser.VarToJson(value) + gtest.Assert(err, nil) + gtest.Assert(b, []byte(`[1,2,3]`)) + }) +} + +func Test_Decode(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.AssertNE(j, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) +} + +func Test_SplitChar(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + j.SetSplitChar(byte('#')) + gtest.AssertNE(j, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m#k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a#1"), 2) + }) +} + +func Test_ViolenceCheck(t *testing.T) { + data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.AssertNE(j, nil) + gtest.Assert(j.Get("m.a.2"), 3) + gtest.Assert(j.Get("m.v1.v2"), nil) + j.SetViolenceCheck(true) + gtest.Assert(j.Get("m.v1.v2"), 4) + }) +} + +func Test_GetToVar(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + var m map[string]string + var n int + var a []int + j := gparser.New(data) + gtest.AssertNE(j, nil) + + j.GetToVar("n", &n) + j.GetToVar("m", &m) + j.GetToVar("a", &a) + + gtest.Assert(n, "123456789") + gtest.Assert(m, g.Map{"k" : "v"}) + gtest.Assert(a, g.Slice{1, 2, 3}) + }) +} + +func Test_GetMap(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.AssertNE(j, nil) + gtest.Assert(j.GetMap("n"), g.Map{}) + gtest.Assert(j.GetMap("m"), g.Map{"k" : "v"}) + gtest.Assert(j.GetMap("a"), g.Map{}) + }) +} + +func Test_GetArray(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.AssertNE(j, nil) + gtest.Assert(j.GetArray("n"), g.Array{123456789}) + gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k":"v"}}) + gtest.Assert(j.GetArray("a"), g.Array{1,2,3}) + }) +} + +func Test_GetString(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.AssertNE(j, nil) + gtest.AssertEQ(j.GetString("n"), "123456789") + gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`) + gtest.AssertEQ(j.GetString("a"), `[1,2,3]`) + gtest.AssertEQ(j.GetString("i"), "") + }) +} + +func Test_GetStrings(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.AssertNE(j, nil) + gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"}) + gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`}) + gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"}) + gtest.AssertEQ(j.GetStrings("i"), g.SliceStr{}) + }) +} + +func Test_GetInterfaces(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + gtest.Case(t, func() { + j := gparser.New(data) + gtest.AssertNE(j, nil) + gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789}) + gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k":"v"}}) + gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1,2,3}) + }) +} + +func Test_Len(t *testing.T) { + gtest.Case(t, func() { + p := gparser.New(nil) + p.Append("a", 1) + p.Append("a", 2) + gtest.Assert(p.Len("a"), 2) + }) + gtest.Case(t, func() { + p := gparser.New(nil) + p.Append("a.b", 1) + p.Append("a.c", 2) + gtest.Assert(p.Len("a"), 2) + }) + gtest.Case(t, func() { + p := gparser.New(nil) + p.Set("a", 1) + gtest.Assert(p.Len("a"), -1) + }) +} + +func Test_Append(t *testing.T) { + gtest.Case(t, func() { + p := gparser.New(nil) + p.Append("a", 1) + p.Append("a", 2) + gtest.Assert(p.Get("a"), g.Slice{1, 2}) + }) + gtest.Case(t, func() { + p := gparser.New(nil) + p.Append("a.b", 1) + p.Append("a.c", 2) + gtest.Assert(p.Get("a"), g.Map{ + "b" : g.Slice{1}, + "c" : g.Slice{2}, + }) + }) + gtest.Case(t, func() { + p := gparser.New(nil) + p.Set("a", 1) + err := p.Append("a", 2) + gtest.AssertNE(err, nil) + gtest.Assert(p.Get("a"), 1) + }) +} + + + diff --git a/g/encoding/gparser/gparser_unit_load_test.go b/g/encoding/gparser/gparser_unit_load_test.go new file mode 100644 index 000000000..930693a72 --- /dev/null +++ b/g/encoding/gparser/gparser_unit_load_test.go @@ -0,0 +1,156 @@ +// 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 gparser_test + +import ( + "github.com/gogf/gf/g" + "github.com/gogf/gf/g/encoding/gparser" + "github.com/gogf/gf/g/os/gfile" + "github.com/gogf/gf/g/test/gtest" + "testing" +) + + +func Test_Load_JSON(t *testing.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + // JSON + gtest.Case(t, func() { + j, err := gparser.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) + // JSON + gtest.Case(t, func() { + path := "test.json" + gfile.PutBinContents(path, data) + defer gfile.Remove(path) + j, err := gparser.Load(path) + gtest.Assert(err, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) +} + +func Test_Load_XML(t *testing.T) { + data := []byte(`123v123456789`) + // XML + gtest.Case(t, func() { + j, err := gparser.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("doc.n"), "123456789") + gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("doc.m.k"), "v") + gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("doc.a.1"), 2) + }) + // XML + gtest.Case(t, func() { + path := "test.xml" + gfile.PutBinContents(path, data) + defer gfile.Remove(path) + j, err := gparser.Load(path) + gtest.Assert(err, nil) + gtest.Assert(j.Get("doc.n"), "123456789") + gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("doc.m.k"), "v") + gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("doc.a.1"), 2) + }) +} + +func Test_Load_YAML1(t *testing.T) { + data := []byte(` +a: +- 1 +- 2 +- 3 +m: + k: v +"n": 123456789 + `) + // YAML + gtest.Case(t, func() { + j, err := gparser.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) + // YAML + gtest.Case(t, func() { + path := "test.yaml" + gfile.PutBinContents(path, data) + defer gfile.Remove(path) + j, err := gparser.Load(path) + gtest.Assert(err, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) +} + +func Test_Load_YAML2(t *testing.T) { + data := []byte("i : 123456789") + gtest.Case(t, func() { + j, err := gparser.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("i"), "123456789") + }) +} + +func Test_Load_TOML1(t *testing.T) { + data := []byte(` +a = ["1", "2", "3"] +n = "123456789" + +[m] + k = "v" +`) + // TOML + gtest.Case(t, func() { + j, err := gparser.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) + // TOML + gtest.Case(t, func() { + path := "test.toml" + gfile.PutBinContents(path, data) + defer gfile.Remove(path) + j, err := gparser.Load(path) + gtest.Assert(err, nil) + gtest.Assert(j.Get("n"), "123456789") + gtest.Assert(j.Get("m"), g.Map{"k" : "v"}) + gtest.Assert(j.Get("m.k"), "v") + gtest.Assert(j.Get("a"), g.Slice{1, 2, 3}) + gtest.Assert(j.Get("a.1"), 2) + }) +} + +func Test_Load_TOML2(t *testing.T) { + data := []byte("i=123456789") + gtest.Case(t, func() { + j, err := gparser.LoadContent(data) + gtest.Assert(err, nil) + gtest.Assert(j.Get("i"), "123456789") + }) +} diff --git a/g/encoding/gparser/gparser_test.go b/g/encoding/gparser/gparser_unit_set_test.go similarity index 92% rename from g/encoding/gparser/gparser_test.go rename to g/encoding/gparser/gparser_unit_set_test.go index 8ce1c8822..2b1d5f532 100644 --- a/g/encoding/gparser/gparser_test.go +++ b/g/encoding/gparser/gparser_unit_set_test.go @@ -4,8 +4,6 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -// 单元测试 - package gparser_test import ( @@ -22,7 +20,6 @@ func Test_Set1(t *testing.T) { }) p.Set("k1.k11", []int{1,2,3}) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, []byte(`{"k1":{"k11":[1,2,3]},"k2":"v2"}`)) != 0 { t.Error("expect:", string(e)) } @@ -36,7 +33,6 @@ func Test_Set2(t *testing.T) { p := gparser.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)) } @@ -48,11 +44,10 @@ func Test_Set2(t *testing.T) { func Test_Set3(t *testing.T) { e := []byte(`{"kv":{"k1":"v1"}}`) p := gparser.New([]string{"a"}) - p.Set("kv", map[string]string{ + p.Set("kv", map[string]string { "k1" : "v1", }) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -68,7 +63,6 @@ func Test_Set4(t *testing.T) { "k1" : "v1", }) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -82,7 +76,6 @@ func Test_Set5(t *testing.T) { p := gparser.New([]string{"a"}) p.Set("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", []int{1,2,3}) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -96,7 +89,6 @@ func Test_Set6(t *testing.T) { p := gparser.New([]string{"a"}) p.Set("1", []int{1,2,3}) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -113,7 +105,6 @@ func Test_Set7(t *testing.T) { }) p.Set("0.1", []int{1,2,3}) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -130,7 +121,6 @@ func Test_Set8(t *testing.T) { }) p.Set("0.0.0.0.0.0.1", []int{1,2,3}) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -147,7 +137,6 @@ func Test_Set9(t *testing.T) { }) p.Set("k1.1", []int{1,2,3}) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -162,7 +151,6 @@ func Test_Set10(t *testing.T) { p := gparser.New(nil) p.Set("a.b.c", 1) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -174,10 +162,9 @@ func Test_Set10(t *testing.T) { func Test_Set11(t *testing.T) { e := []byte(`{"a":{"b":{}}}`) - p, _ := gparser.LoadContent([]byte(`{"a":{"b":{"c":1}}}`), "json") + p, _ := gparser.LoadContent([]byte(`{"a":{"b":{"c":1}}}`)) p.Remove("a.b.c") if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -192,7 +179,6 @@ func Test_Set12(t *testing.T) { p.Set("0", 0) p.Set("1", 1) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -207,7 +193,6 @@ func Test_Set13(t *testing.T) { p.Set("array.0", 0) p.Set("array.1", 1) if c, err := p.ToJson(); err == nil { - if bytes.Compare(c, e) != 0 { t.Error("expect:", string(e)) } @@ -216,7 +201,16 @@ func Test_Set13(t *testing.T) { } } - - - - +func Test_Set14(t *testing.T) { + e := []byte(`{"f":{"a":1}}`) + p := gparser.New(nil) + p.Set("f", "m") + p.Set("f.a", 1) + if c, err := p.ToJson(); err == nil { + if bytes.Compare(c, e) != 0 { + t.Error("expect:", string(e)) + } + } else { + t.Error(err) + } +} diff --git a/g/net/ghttp/ghttp_server_admin_process.go b/g/net/ghttp/ghttp_server_admin_process.go index 376935344..70865c4d1 100644 --- a/g/net/ghttp/ghttp_server_admin_process.go +++ b/g/net/ghttp/ghttp_server_admin_process.go @@ -168,7 +168,7 @@ func getServerFdMap() map[string]listenerFdMap { func bufferToServerFdMap(buffer []byte) map[string]listenerFdMap { sfm := make(map[string]listenerFdMap) if len(buffer) > 0 { - j, _ := gjson.LoadContent(buffer, "json") + j, _ := gjson.LoadContent(buffer) for k, _ := range j.ToMap() { m := make(map[string]string) for k, v := range j.GetMap(k) {