2017-12-29 16:03:30 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://gitee.com/johng/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://gitee.com/johng/gf.
|
|
|
|
|
|
2018-01-03 10:53:45 +08:00
|
|
|
|
// JSON解析/封装
|
2017-11-23 10:21:28 +08:00
|
|
|
|
package gjson
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"strings"
|
|
|
|
|
"strconv"
|
2017-12-14 17:32:51 +08:00
|
|
|
|
"io/ioutil"
|
2017-12-25 17:04:54 +08:00
|
|
|
|
"encoding/json"
|
2018-01-19 15:26:28 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/gfile"
|
2018-01-19 16:19:48 +08:00
|
|
|
|
"gitee.com/johng/gf/g/util/gconv"
|
2018-01-19 15:26:28 +08:00
|
|
|
|
"gitee.com/johng/gf/g/encoding/gxml"
|
2018-01-19 16:19:48 +08:00
|
|
|
|
"gitee.com/johng/gf/g/encoding/gyaml"
|
2018-01-20 11:09:27 +08:00
|
|
|
|
"gitee.com/johng/gf/g/encoding/gtoml"
|
2017-11-23 10:21:28 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// json解析结果存放数组
|
|
|
|
|
type Json struct {
|
2018-01-22 17:55:12 +08:00
|
|
|
|
p *interface{} // 注意这是一个指针
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 编码go变量为json字符串,并返回json字符串指针
|
2017-12-25 17:04:54 +08:00
|
|
|
|
func Encode (v interface{}) ([]byte, error) {
|
|
|
|
|
return json.Marshal(v)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解码字符串为interface{}变量
|
2017-12-25 17:04:54 +08:00
|
|
|
|
func Decode (b []byte) (interface{}, error) {
|
2017-11-23 10:21:28 +08:00
|
|
|
|
var v interface{}
|
2018-01-11 18:02:56 +08:00
|
|
|
|
if err := DecodeTo(b, &v); err != nil {
|
2017-12-13 17:35:43 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
} else {
|
|
|
|
|
return v, nil
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-19 15:26:28 +08:00
|
|
|
|
// 解析json字符串为go变量,注意第二个参数为指针(任意结构的变量)
|
2017-12-25 17:04:54 +08:00
|
|
|
|
func DecodeTo (b []byte, v interface{}) error {
|
|
|
|
|
return json.Unmarshal(b, v)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解析json字符串为gjson.Json对象,并返回操作对象指针
|
2017-12-25 17:04:54 +08:00
|
|
|
|
func DecodeToJson (b []byte) (*Json, error) {
|
|
|
|
|
if v, err := Decode(b); err != nil {
|
2017-12-13 17:35:43 +08:00
|
|
|
|
return nil, err
|
2018-01-11 18:02:56 +08:00
|
|
|
|
} else {
|
|
|
|
|
return &Json{&v}, nil
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-19 15:26:28 +08:00
|
|
|
|
// 支持多种配置文件类型转换为json格式内容并解析为gjson.Json对象
|
2017-12-14 17:32:51 +08:00
|
|
|
|
func Load (path string) (*Json, error) {
|
|
|
|
|
data, err := ioutil.ReadFile(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-01-19 16:19:48 +08:00
|
|
|
|
return LoadContent(data, gfile.Ext(path))
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-20 11:09:27 +08:00
|
|
|
|
// 支持的配置文件格式:xml, json, yaml/yml, toml
|
2018-01-19 16:19:48 +08:00
|
|
|
|
func LoadContent (data []byte, t string) (*Json, error) {
|
|
|
|
|
var err error
|
|
|
|
|
var result interface{}
|
|
|
|
|
switch t {
|
2018-01-20 11:09:27 +08:00
|
|
|
|
case "xml": fallthrough
|
2018-01-19 15:26:28 +08:00
|
|
|
|
case ".xml":
|
|
|
|
|
data, err = gxml.ToJson(data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-01-20 11:09:27 +08:00
|
|
|
|
case "yml": fallthrough
|
|
|
|
|
case "yaml": fallthrough
|
|
|
|
|
case ".yml": fallthrough
|
2018-01-19 16:19:48 +08:00
|
|
|
|
case ".yaml":
|
|
|
|
|
data, err = gyaml.ToJson(data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-01-20 11:09:27 +08:00
|
|
|
|
|
|
|
|
|
case "toml": fallthrough
|
|
|
|
|
case ".toml":
|
|
|
|
|
data, err = gtoml.ToJson(data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-01-19 15:26:28 +08:00
|
|
|
|
}
|
2017-12-14 17:32:51 +08:00
|
|
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return &Json{ &result }, nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 10:21:28 +08:00
|
|
|
|
// 将变量转换为Json对象进行处理,该变量至少应当是一个map或者array,否者转换没有意义
|
|
|
|
|
func NewJson(v *interface{}) *Json {
|
|
|
|
|
return &Json{ v }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil
|
|
|
|
|
// 注意第二个参数需要给的是变量地址
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetToVar(pattern string, v interface{}) error {
|
|
|
|
|
r := j.Get(pattern)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
if r != nil {
|
2017-12-13 17:35:43 +08:00
|
|
|
|
if t, err := Encode(r); err == nil {
|
|
|
|
|
return DecodeTo(t, v)
|
|
|
|
|
} else {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2017-11-23 10:21:28 +08:00
|
|
|
|
} else {
|
|
|
|
|
v = nil
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换
|
|
|
|
|
// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetMap(pattern string) map[string]interface{} {
|
|
|
|
|
result := j.Get(pattern)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
if result != nil {
|
|
|
|
|
if r, ok := result.(map[string]interface{}); ok {
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-18 11:07:44 +08:00
|
|
|
|
// 将检索值转换为Json对象指针返回
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetJson(pattern string) *Json {
|
|
|
|
|
result := j.Get(pattern)
|
2017-12-18 11:07:44 +08:00
|
|
|
|
if result != nil {
|
|
|
|
|
return &Json{&result}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 10:21:28 +08:00
|
|
|
|
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
|
|
|
|
|
// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetArray(pattern string) []interface{} {
|
|
|
|
|
result := j.Get(pattern)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
if result != nil {
|
|
|
|
|
if r, ok := result.([]interface{}); ok {
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 返回指定json中的string
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetString(pattern string) string {
|
|
|
|
|
return gconv.String(j.Get(pattern))
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-31 11:09:16 +08:00
|
|
|
|
// 返回指定json中的bool(false:"", 0, false, off)
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetBool(pattern string) bool {
|
|
|
|
|
return gconv.Bool(j.Get(pattern))
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetInt(pattern string) int {
|
|
|
|
|
return gconv.Int(j.Get(pattern))
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetUint(pattern string) uint {
|
|
|
|
|
return gconv.Uint(j.Get(pattern))
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetFloat32(pattern string) float32 {
|
|
|
|
|
return gconv.Float32(j.Get(pattern))
|
2017-12-31 11:09:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) GetFloat64(pattern string) float64 {
|
|
|
|
|
return gconv.Float64(j.Get(pattern))
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
// 根据pattern查找并设置数据
|
|
|
|
|
// 注意:写入的时候"."符号只能表示层级,不能使用带"."符号的键名
|
|
|
|
|
func (j *Json) Set(pattern string, value interface{}) error {
|
|
|
|
|
array := strings.Split(pattern, ".")
|
|
|
|
|
// root节点
|
|
|
|
|
if len(array) == 1 {
|
|
|
|
|
return j.setRoot(pattern, value)
|
|
|
|
|
}
|
|
|
|
|
pointer := j.p
|
2017-11-23 10:21:28 +08:00
|
|
|
|
length := len(array)
|
|
|
|
|
for i:= 0; i < length; i++ {
|
|
|
|
|
switch (*pointer).(type) {
|
|
|
|
|
case map[string]interface{}:
|
2018-01-22 17:55:12 +08:00
|
|
|
|
if i == length - 1 {
|
|
|
|
|
(*pointer).(map[string]interface{})[array[i]] = value
|
2017-11-23 10:21:28 +08:00
|
|
|
|
} else {
|
2018-01-22 17:55:12 +08:00
|
|
|
|
v, ok := (*pointer).(map[string]interface{})[array[i]]
|
|
|
|
|
if !ok {
|
|
|
|
|
if strings.Compare(array[i], "0") == 0 {
|
|
|
|
|
v = make([]interface{}, 0)
|
|
|
|
|
} else {
|
|
|
|
|
v = make(map[string]interface{})
|
|
|
|
|
}
|
|
|
|
|
(*pointer).(map[string]interface{})[array[i]] = v
|
|
|
|
|
}
|
|
|
|
|
pointer = &v
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
case []interface{}:
|
|
|
|
|
if isNumeric(array[i]) {
|
2018-01-22 17:55:12 +08:00
|
|
|
|
if n, err := strconv.Atoi(array[i]); err == nil {
|
2017-11-23 10:21:28 +08:00
|
|
|
|
if i == length - 1 {
|
2018-01-22 17:55:12 +08:00
|
|
|
|
(*pointer).([]interface{})[n] = value
|
|
|
|
|
if len((*pointer).([]interface{})) > n {
|
|
|
|
|
(*pointer).([]interface{})[n] = value
|
|
|
|
|
} else {
|
|
|
|
|
// 注意这里产生了临时变量和赋值拷贝
|
|
|
|
|
array := (*pointer).([]interface{})
|
|
|
|
|
array = append(array, value)
|
|
|
|
|
*pointer = array
|
|
|
|
|
}
|
|
|
|
|
break
|
2017-11-23 10:21:28 +08:00
|
|
|
|
} else {
|
|
|
|
|
pointer = &(*pointer).([]interface{})[n]
|
|
|
|
|
}
|
2018-01-22 17:55:12 +08:00
|
|
|
|
} else {
|
|
|
|
|
return err
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
2018-01-22 17:55:12 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 修改根节点数据
|
|
|
|
|
func (j *Json) setRoot(pattern string, value interface{}) error {
|
|
|
|
|
switch (*j.p).(type) {
|
|
|
|
|
case map[string]interface{}:
|
|
|
|
|
(*j.p).(map[string]interface{})[pattern] = value
|
|
|
|
|
case []interface{}:
|
|
|
|
|
if isNumeric(pattern) {
|
|
|
|
|
if n, err := strconv.Atoi(pattern); err != nil {
|
|
|
|
|
return err
|
2017-11-23 10:21:28 +08:00
|
|
|
|
} else {
|
2018-01-22 17:55:12 +08:00
|
|
|
|
if len((*j.p).([]interface{})) > n {
|
|
|
|
|
(*j.p).([]interface{})[n] = value
|
|
|
|
|
} else {
|
|
|
|
|
// 注意这里产生了临时变量和赋值拷贝
|
|
|
|
|
array := (*j.p).([]interface{})
|
|
|
|
|
array = append(array, value)
|
|
|
|
|
*j.p = array
|
|
|
|
|
}
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
2018-01-22 17:55:12 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"
|
|
|
|
|
// 返回的结果类型的interface{},因此需要自己做类型转换
|
|
|
|
|
// 如果找不到对应节点的数据,返回nil
|
|
|
|
|
func (j *Json) Get(pattern string) interface{} {
|
|
|
|
|
if r := j.getPointerByPattern(pattern); r != nil {
|
|
|
|
|
return *r
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据pattern层级查找变量指针
|
|
|
|
|
func (j *Json) getPointerByPattern(pattern string) *interface{} {
|
|
|
|
|
start := 0
|
|
|
|
|
index := len(pattern)
|
|
|
|
|
length := 0
|
|
|
|
|
pointer := j.p
|
|
|
|
|
for {
|
|
|
|
|
if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil {
|
|
|
|
|
length += index - start
|
|
|
|
|
if start > 0 {
|
|
|
|
|
length += 1
|
|
|
|
|
}
|
|
|
|
|
start = index + 1
|
|
|
|
|
index = len(pattern)
|
|
|
|
|
if length == len(pattern) {
|
|
|
|
|
return r
|
|
|
|
|
} else {
|
|
|
|
|
pointer = r
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
index = strings.LastIndex(pattern[start:index], ".")
|
|
|
|
|
}
|
|
|
|
|
if start >= index {
|
|
|
|
|
break
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-22 17:55:12 +08:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断给定的pattern在当前的pointer下是否有值,并返回对应的pointer
|
|
|
|
|
// 注意这里返回的指针都是临时变量的内存地址
|
|
|
|
|
func (j *Json) checkPatternByPointer(pattern string, pointer *interface{}) *interface{} {
|
|
|
|
|
switch (*pointer).(type) {
|
|
|
|
|
case map[string]interface{}:
|
|
|
|
|
if v, ok := (*pointer).(map[string]interface{})[pattern]; ok {
|
|
|
|
|
return &v
|
|
|
|
|
}
|
|
|
|
|
case []interface{}:
|
|
|
|
|
if isNumeric(pattern) {
|
|
|
|
|
n, err := strconv.Atoi(pattern)
|
|
|
|
|
if err == nil && len((*pointer).([]interface{})) > n {
|
|
|
|
|
return &(*pointer).([]interface{})[n]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 转换为map[string]interface{}类型,如果转换失败,返回nil
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToMap() map[string]interface{} {
|
|
|
|
|
switch (*(j.p)).(type) {
|
2017-11-23 10:21:28 +08:00
|
|
|
|
case map[string]interface{}:
|
2018-01-22 17:55:12 +08:00
|
|
|
|
return (*(j.p)).(map[string]interface{})
|
2017-11-23 10:21:28 +08:00
|
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 转换为[]interface{}类型,如果转换失败,返回nil
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToArray() []interface{} {
|
|
|
|
|
switch (*(j.p)).(type) {
|
2017-11-23 10:21:28 +08:00
|
|
|
|
case []interface{}:
|
2018-01-22 17:55:12 +08:00
|
|
|
|
return (*(j.p)).([]interface{})
|
2017-11-23 10:21:28 +08:00
|
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToXml(rootTag...string) ([]byte, error) {
|
|
|
|
|
return gxml.Encode(j.ToMap(), rootTag...)
|
2018-01-19 16:19:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToXmlIndent(rootTag...string) ([]byte, error) {
|
|
|
|
|
return gxml.EncodeWithIndent(j.ToMap(), rootTag...)
|
2018-01-19 16:19:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToJson() ([]byte, error) {
|
|
|
|
|
return Encode(*(j.p))
|
2018-01-19 16:19:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToJsonIndent() ([]byte, error) {
|
|
|
|
|
return json.MarshalIndent(*(j.p), "", "\t")
|
2018-01-19 16:19:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToYaml() ([]byte, error) {
|
|
|
|
|
return gyaml.Encode(*(j.p))
|
2018-01-19 16:19:48 +08:00
|
|
|
|
}
|
2017-11-23 10:21:28 +08:00
|
|
|
|
|
2018-01-22 17:55:12 +08:00
|
|
|
|
func (j *Json) ToToml() ([]byte, error) {
|
|
|
|
|
return gtoml.Encode(*(j.p))
|
2018-01-20 11:09:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 10:21:28 +08:00
|
|
|
|
// 判断所给字符串是否为数字
|
|
|
|
|
func isNumeric(s string) bool {
|
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
|
|
|
if s[i] < byte('0') || s[i] > byte('9') {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|