gf/g/encoding/gjson/gjson.go

365 lines
11 KiB
Go
Raw Normal View History

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"
"io/ioutil"
"encoding/json"
2018-01-19 15:26:28 +08:00
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/util/gconv"
2018-01-19 15:26:28 +08:00
"gitee.com/johng/gf/g/encoding/gxml"
"gitee.com/johng/gf/g/encoding/gyaml"
"gitee.com/johng/gf/g/encoding/gtoml"
2017-11-23 10:21:28 +08:00
)
// json解析结果存放数组
type Json struct {
p *interface{} // 注意这是一个指针
2017-11-23 10:21:28 +08:00
}
// 编码go变量为json字符串并返回json字符串指针
func Encode (v interface{}) ([]byte, error) {
return json.Marshal(v)
2017-11-23 10:21:28 +08:00
}
// 解码字符串为interface{}变量
func Decode (b []byte) (interface{}, error) {
2017-11-23 10:21:28 +08:00
var v interface{}
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变量注意第二个参数为指针(任意结构的变量)
func DecodeTo (b []byte, v interface{}) error {
return json.Unmarshal(b, v)
2017-11-23 10:21:28 +08:00
}
// 解析json字符串为gjson.Json对象并返回操作对象指针
func DecodeToJson (b []byte) (*Json, error) {
if v, err := Decode(b); err != nil {
2017-12-13 17:35:43 +08:00
return nil, err
} else {
return &Json{&v}, nil
2017-11-23 10:21:28 +08:00
}
}
2018-01-19 15:26:28 +08:00
// 支持多种配置文件类型转换为json格式内容并解析为gjson.Json对象
func Load (path string) (*Json, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return LoadContent(data, gfile.Ext(path))
}
// 支持的配置文件格式xml, json, yaml/yml, toml
func LoadContent (data []byte, t string) (*Json, error) {
var err error
var result interface{}
switch t {
case "xml": fallthrough
2018-01-19 15:26:28 +08:00
case ".xml":
data, err = gxml.ToJson(data)
if err != nil {
return nil, err
}
case "yml": fallthrough
case "yaml": fallthrough
case ".yml": fallthrough
case ".yaml":
data, err = gyaml.ToJson(data)
if err != nil {
return nil, err
}
case "toml": fallthrough
case ".toml":
data, err = gtoml.ToJson(data)
if err != nil {
return nil, err
}
2018-01-19 15:26:28 +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
// 注意第二个参数需要给的是变量地址
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
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
}
// 将检索值转换为Json对象指针返回
func (j *Json) GetJson(pattern string) *Json {
result := j.Get(pattern)
if result != nil {
return &Json{&result}
}
return nil
}
2017-11-23 10:21:28 +08:00
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与json类型不匹配那么将会返回nil
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
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)
func (j *Json) GetBool(pattern string) bool {
return gconv.Bool(j.Get(pattern))
2017-11-23 10:21:28 +08:00
}
func (j *Json) GetInt(pattern string) int {
return gconv.Int(j.Get(pattern))
2017-11-23 10:21:28 +08:00
}
func (j *Json) GetUint(pattern string) uint {
return gconv.Uint(j.Get(pattern))
2017-11-23 10:21:28 +08:00
}
func (j *Json) GetFloat32(pattern string) float32 {
return gconv.Float32(j.Get(pattern))
2017-12-31 11:09:16 +08:00
}
func (j *Json) GetFloat64(pattern string) float64 {
return gconv.Float64(j.Get(pattern))
2017-11-23 10:21:28 +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{}:
if i == length - 1 {
(*pointer).(map[string]interface{})[array[i]] = value
2017-11-23 10:21:28 +08:00
} else {
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]) {
if n, err := strconv.Atoi(array[i]); err == nil {
2017-11-23 10:21:28 +08:00
if i == length - 1 {
(*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]
}
} else {
return err
2017-11-23 10:21:28 +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 {
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
}
}
}
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
}
}
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
func (j *Json) ToMap() map[string]interface{} {
switch (*(j.p)).(type) {
2017-11-23 10:21:28 +08:00
case map[string]interface{}:
return (*(j.p)).(map[string]interface{})
2017-11-23 10:21:28 +08:00
default:
return nil
}
}
// 转换为[]interface{}类型,如果转换失败返回nil
func (j *Json) ToArray() []interface{} {
switch (*(j.p)).(type) {
2017-11-23 10:21:28 +08:00
case []interface{}:
return (*(j.p)).([]interface{})
2017-11-23 10:21:28 +08:00
default:
return nil
}
}
func (j *Json) ToXml(rootTag...string) ([]byte, error) {
return gxml.Encode(j.ToMap(), rootTag...)
}
func (j *Json) ToXmlIndent(rootTag...string) ([]byte, error) {
return gxml.EncodeWithIndent(j.ToMap(), rootTag...)
}
func (j *Json) ToJson() ([]byte, error) {
return Encode(*(j.p))
}
func (j *Json) ToJsonIndent() ([]byte, error) {
return json.MarshalIndent(*(j.p), "", "\t")
}
func (j *Json) ToYaml() ([]byte, error) {
return gyaml.Encode(*(j.p))
}
2017-11-23 10:21:28 +08:00
func (j *Json) ToToml() ([]byte, error) {
return gtoml.Encode(*(j.p))
}
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
}