mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
初步完善gjson功能,新增gparser包,用于编码/解析json,xml,yaml,toml数据格式内容
This commit is contained in:
@ -8,6 +8,8 @@
|
||||
package gjson
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"errors"
|
||||
"strings"
|
||||
"strconv"
|
||||
"io/ioutil"
|
||||
@ -21,7 +23,8 @@ import (
|
||||
|
||||
// json解析结果存放数组
|
||||
type Json struct {
|
||||
p *interface{} // 注意这是一个指针
|
||||
mu sync.RWMutex
|
||||
p *interface{} // 注意这是一个指针
|
||||
}
|
||||
|
||||
// 编码go变量为json字符串,并返回json字符串指针
|
||||
@ -49,7 +52,7 @@ func DecodeToJson (b []byte) (*Json, error) {
|
||||
if v, err := Decode(b); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &Json{&v}, nil
|
||||
return NewJson(&v), nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,12 +95,12 @@ func LoadContent (data []byte, t string) (*Json, error) {
|
||||
if err := json.Unmarshal(data, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Json{ &result }, nil
|
||||
return NewJson(&result), nil
|
||||
}
|
||||
|
||||
// 将变量转换为Json对象进行处理,该变量至少应当是一个map或者array,否者转换没有意义
|
||||
func NewJson(v *interface{}) *Json {
|
||||
return &Json{ v }
|
||||
return &Json{ p: v }
|
||||
}
|
||||
|
||||
// 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil
|
||||
@ -132,7 +135,7 @@ func (j *Json) GetMap(pattern string) map[string]interface{} {
|
||||
func (j *Json) GetJson(pattern string) *Json {
|
||||
result := j.Get(pattern)
|
||||
if result != nil {
|
||||
return &Json{&result}
|
||||
return NewJson(&result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -178,11 +181,13 @@ func (j *Json) GetFloat64(pattern string) float64 {
|
||||
// 根据pattern查找并设置数据
|
||||
// 注意:写入的时候"."符号只能表示层级,不能使用带"."符号的键名
|
||||
func (j *Json) Set(pattern string, value interface{}) error {
|
||||
value = j.convertValue(value)
|
||||
array := strings.Split(pattern, ".")
|
||||
// root节点
|
||||
if len(array) == 1 {
|
||||
return j.setRoot(pattern, value)
|
||||
}
|
||||
j.mu.Lock()
|
||||
pointer := j.p
|
||||
length := len(array)
|
||||
for i:= 0; i < length; i++ {
|
||||
@ -206,28 +211,49 @@ func (j *Json) Set(pattern string, value interface{}) error {
|
||||
if isNumeric(array[i]) {
|
||||
if n, err := strconv.Atoi(array[i]); err == nil {
|
||||
if i == length - 1 {
|
||||
(*pointer).([]interface{})[n] = value
|
||||
if len((*pointer).([]interface{})) > n {
|
||||
if cap((*pointer).([]interface{})) >= n {
|
||||
(*pointer).([]interface{})[n] = value
|
||||
} else {
|
||||
// 注意这里产生了临时变量和赋值拷贝
|
||||
array := (*pointer).([]interface{})
|
||||
array = append(array, value)
|
||||
*pointer = array
|
||||
s := make([]interface{}, n + 1)
|
||||
copy(s, (*pointer).([]interface{}))
|
||||
s[n] = value
|
||||
j.mu.Unlock()
|
||||
return j.Set(strings.Join(array[0 : i], "."), s)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
pointer = &(*pointer).([]interface{})[n]
|
||||
}
|
||||
} else {
|
||||
j.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
j.mu.Unlock()
|
||||
return errors.New("\"" + strings.Join(array[0:i], ".") + "\" is array, invalid index - \"" + array[i] + "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
j.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 数据结构转换,map参数必须转换为map[string]interface{},数组参数必须转换为[]interface{}
|
||||
func (j *Json) convertValue(value interface{}) interface{} {
|
||||
switch value.(type) {
|
||||
case map[string]interface{}:
|
||||
return value
|
||||
case []interface{}:
|
||||
return value
|
||||
default:
|
||||
// 这里效率会比较低
|
||||
b, _ := Encode(value)
|
||||
v, _ := Decode(b)
|
||||
return v
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// 修改根节点数据
|
||||
func (j *Json) setRoot(pattern string, value interface{}) error {
|
||||
switch (*j.p).(type) {
|
||||
@ -238,7 +264,7 @@ func (j *Json) setRoot(pattern string, value interface{}) error {
|
||||
if n, err := strconv.Atoi(pattern); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if len((*j.p).([]interface{})) > n {
|
||||
if cap((*j.p).([]interface{})) >= n {
|
||||
(*j.p).([]interface{})[n] = value
|
||||
} else {
|
||||
// 注意这里产生了临时变量和赋值拷贝
|
||||
@ -256,6 +282,8 @@ func (j *Json) setRoot(pattern string, value interface{}) error {
|
||||
// 返回的结果类型的interface{},因此需要自己做类型转换
|
||||
// 如果找不到对应节点的数据,返回nil
|
||||
func (j *Json) Get(pattern string) interface{} {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
if r := j.getPointerByPattern(pattern); r != nil {
|
||||
return *r
|
||||
}
|
||||
@ -312,6 +340,8 @@ func (j *Json) checkPatternByPointer(pattern string, pointer *interface{}) *inte
|
||||
|
||||
// 转换为map[string]interface{}类型,如果转换失败,返回nil
|
||||
func (j *Json) ToMap() map[string]interface{} {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
switch (*(j.p)).(type) {
|
||||
case map[string]interface{}:
|
||||
return (*(j.p)).(map[string]interface{})
|
||||
@ -322,6 +352,8 @@ func (j *Json) ToMap() map[string]interface{} {
|
||||
|
||||
// 转换为[]interface{}类型,如果转换失败,返回nil
|
||||
func (j *Json) ToArray() []interface{} {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
switch (*(j.p)).(type) {
|
||||
case []interface{}:
|
||||
return (*(j.p)).([]interface{})
|
||||
@ -339,18 +371,26 @@ func (j *Json) ToXmlIndent(rootTag...string) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (j *Json) ToJson() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
return Encode(*(j.p))
|
||||
}
|
||||
|
||||
func (j *Json) ToJsonIndent() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
return json.MarshalIndent(*(j.p), "", "\t")
|
||||
}
|
||||
|
||||
func (j *Json) ToYaml() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
return gyaml.Encode(*(j.p))
|
||||
}
|
||||
|
||||
func (j *Json) ToToml() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
return gtoml.Encode(*(j.p))
|
||||
}
|
||||
|
||||
|
||||
150
g/encoding/gparser/gparser.go
Normal file
150
g/encoding/gparser/gparser.go
Normal file
@ -0,0 +1,150 @@
|
||||
// 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.
|
||||
|
||||
// 数据文件编码/解析.
|
||||
package gparser
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/encoding/gjson"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
json *gjson.Json
|
||||
}
|
||||
|
||||
func Load (path string) (*File, error) {
|
||||
if j, e := gjson.Load(path); e == nil {
|
||||
return &File{j}, nil
|
||||
} else {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
|
||||
// 支持的配置文件格式:xml, json, yaml/yml, toml
|
||||
func LoadContent (data []byte, fileType string) (*File, error) {
|
||||
if j, e := gjson.LoadContent(data, fileType); e == nil {
|
||||
return &File{j}, nil
|
||||
} else {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
|
||||
// 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil
|
||||
// 注意第二个参数需要给的是变量地址
|
||||
func (f *File) GetToVar(pattern string, v interface{}) error {
|
||||
return f.json.GetToVar(pattern, v)
|
||||
}
|
||||
|
||||
// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换
|
||||
// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil
|
||||
func (f *File) GetMap(pattern string) map[string]interface{} {
|
||||
return f.json.GetMap(pattern)
|
||||
}
|
||||
|
||||
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
|
||||
// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil
|
||||
func (f *File) GetArray(pattern string) []interface{} {
|
||||
return f.json.GetArray(pattern)
|
||||
}
|
||||
|
||||
// 返回指定json中的string
|
||||
func (f *File) GetString(pattern string) string {
|
||||
return f.json.GetString(pattern)
|
||||
}
|
||||
|
||||
// 返回指定json中的bool(false:"", 0, false, off)
|
||||
func (f *File) GetBool(pattern string) bool {
|
||||
return f.json.GetBool(pattern)
|
||||
}
|
||||
|
||||
func (f *File) GetInt(pattern string) int {
|
||||
return f.json.GetInt(pattern)
|
||||
}
|
||||
|
||||
func (f *File) GetUint(pattern string) uint {
|
||||
return f.json.GetUint(pattern)
|
||||
}
|
||||
|
||||
func (f *File) GetFloat32(pattern string) float32 {
|
||||
return f.json.GetFloat32(pattern)
|
||||
}
|
||||
|
||||
func (f *File) GetFloat64(pattern string) float64 {
|
||||
return f.json.GetFloat64(pattern)
|
||||
}
|
||||
|
||||
// 根据pattern查找并设置数据
|
||||
// 注意:写入的时候"."符号只能表示层级,不能使用带"."符号的键名
|
||||
func (f *File) Set(pattern string, value interface{}) error {
|
||||
return f.json.Set(pattern, value)
|
||||
}
|
||||
|
||||
// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"
|
||||
// 返回的结果类型的interface{},因此需要自己做类型转换
|
||||
// 如果找不到对应节点的数据,返回nil
|
||||
func (f *File) Get(pattern string) interface{} {
|
||||
return f.json.Get(pattern)
|
||||
}
|
||||
|
||||
// 转换为map[string]interface{}类型,如果转换失败,返回nil
|
||||
func (f *File) ToMap() map[string]interface{} {
|
||||
return f.json.ToMap()
|
||||
}
|
||||
|
||||
// 转换为[]interface{}类型,如果转换失败,返回nil
|
||||
func (f *File) ToArray() []interface{} {
|
||||
return f.json.ToArray()
|
||||
}
|
||||
|
||||
/* 以下为数据文件格式转换,支持类型:xml, json, yaml/yml, toml */
|
||||
|
||||
func (f *File) ToXml(rootTag...string) ([]byte, error) {
|
||||
return f.json.ToXml(rootTag...)
|
||||
}
|
||||
|
||||
func (f *File) ToXmlIndent(rootTag...string) ([]byte, error) {
|
||||
return f.json.ToXmlIndent(rootTag...)
|
||||
}
|
||||
|
||||
func (f *File) ToJson() ([]byte, error) {
|
||||
return f.json.ToJson()
|
||||
}
|
||||
|
||||
func (f *File) ToJsonIndent() ([]byte, error) {
|
||||
return f.json.ToJsonIndent()
|
||||
}
|
||||
|
||||
func (f *File) ToYaml() ([]byte, error) {
|
||||
return f.json.ToYaml()
|
||||
}
|
||||
|
||||
func (f *File) ToToml() ([]byte, error) {
|
||||
return f.json.ToToml()
|
||||
}
|
||||
|
||||
func VarToXml(value interface{}, rootTag...string) ([]byte, error) {
|
||||
return gjson.NewJson(&value).ToXml(rootTag...)
|
||||
}
|
||||
|
||||
func VarToXmlIndent(value interface{}, rootTag...string) ([]byte, error) {
|
||||
return gjson.NewJson(&value).ToXmlIndent(rootTag...)
|
||||
}
|
||||
|
||||
func VarToJson(value interface{}) ([]byte, error) {
|
||||
return gjson.NewJson(&value).ToJson()
|
||||
}
|
||||
|
||||
func VarToJsonIndent(value interface{}) ([]byte, error) {
|
||||
return gjson.NewJson(&value).ToJsonIndent()
|
||||
}
|
||||
|
||||
func VarToYaml(value interface{}) ([]byte, error) {
|
||||
return gjson.NewJson(&value).ToYaml()
|
||||
}
|
||||
|
||||
func VarToToml(value interface{}) ([]byte, error) {
|
||||
return gjson.NewJson(&value).ToToml()
|
||||
}
|
||||
@ -8,9 +8,8 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"gitee.com/johng/gf/g/encoding/gjson"
|
||||
"sync"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// 服务端请求返回对象
|
||||
@ -21,11 +20,11 @@ type Response struct {
|
||||
}
|
||||
|
||||
// 返回的固定JSON数据结构
|
||||
type ResponseJson struct {
|
||||
Result int `json:"result"` // 标识消息状态
|
||||
Message string `json:"message"` // 消息使用string存储
|
||||
Data []byte `json:"data"` // 二进制数据(不管什么数据结构)
|
||||
}
|
||||
//type ResponseJson struct {
|
||||
// Result int `json:"result"` // 标识消息状态
|
||||
// Message string `json:"message"` // 消息使用string存储
|
||||
// Data []byte `json:"data"` // 二进制数据(不管什么数据结构)
|
||||
//}
|
||||
|
||||
// 返回信息(byte)
|
||||
func (r *Response) Write(content []byte) {
|
||||
@ -42,17 +41,17 @@ func (r *Response) WriteString(content string) {
|
||||
}
|
||||
|
||||
// 返回固定格式的json
|
||||
func (r *Response) WriteJson(result int, message string, data []byte) error {
|
||||
r.Header().Set("Content-Type", "application/json")
|
||||
r.bufmu.Lock()
|
||||
defer r.bufmu.Unlock()
|
||||
if jsonstr, err := gjson.Encode(ResponseJson{ result, message, data }); err != nil {
|
||||
return err
|
||||
} else {
|
||||
r.buffer = append(r.buffer, jsonstr...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
//func (r *Response) WriteJson(result int, message string, data []byte) error {
|
||||
// r.Header().Set("Content-Type", "application/json")
|
||||
// r.bufmu.Lock()
|
||||
// defer r.bufmu.Unlock()
|
||||
// if jsonstr, err := gjson.Encode(ResponseJson{ result, message, data }); err != nil {
|
||||
// return err
|
||||
// } else {
|
||||
// r.buffer = append(r.buffer, jsonstr...)
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
|
||||
// 获取当前缓冲区中的数据
|
||||
func (r *Response) Buffer() []byte {
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
gDEFAULT_CONFIG_FILE = "config.json" // 默认的配置管理文件名称
|
||||
gDEFAULT_CONFIG_FILE = "config.yml" // 默认的配置管理文件名称
|
||||
)
|
||||
|
||||
// 配置管理对象
|
||||
|
||||
@ -42,6 +42,59 @@ func testMultiDots() {
|
||||
}
|
||||
}
|
||||
|
||||
// 设置数据
|
||||
func testSet() {
|
||||
data :=
|
||||
`{
|
||||
"users" : {
|
||||
"count" : 100
|
||||
}
|
||||
}`
|
||||
j, err := gjson.DecodeToJson([]byte(data))
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
j.Set("users.count", 2)
|
||||
j.Set("users.list", []string{"John", "小明"})
|
||||
c, _ := j.ToJson()
|
||||
fmt.Println(string(c))
|
||||
}
|
||||
}
|
||||
|
||||
// 将Json数据转换为其他数据格式
|
||||
func testConvert() {
|
||||
data :=
|
||||
`{
|
||||
"users" : {
|
||||
"count" : 100,
|
||||
"list" : ["John", "小明"]
|
||||
}
|
||||
}`
|
||||
j, err := gjson.DecodeToJson([]byte(data))
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
c, _ := j.ToJson()
|
||||
fmt.Println("JSON:")
|
||||
fmt.Println(string(c))
|
||||
fmt.Println("======================")
|
||||
|
||||
fmt.Println("XML:")
|
||||
c, _ = j.ToXmlIndent()
|
||||
fmt.Println(string(c))
|
||||
fmt.Println("======================")
|
||||
|
||||
fmt.Println("YAML:")
|
||||
c, _ = j.ToYaml()
|
||||
fmt.Println(string(c))
|
||||
fmt.Println("======================")
|
||||
|
||||
fmt.Println("TOML:")
|
||||
c, _ = j.ToToml()
|
||||
fmt.Println(string(c))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
testMultiDots()
|
||||
testConvert()
|
||||
}
|
||||
24
geg/frame/config.toml
Normal file
24
geg/frame/config.toml
Normal file
@ -0,0 +1,24 @@
|
||||
# 模板引擎目录
|
||||
viewpath = "/home/www/templates/"
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
[[database.default]]
|
||||
host = "127.0.0.1"
|
||||
port = "3306"
|
||||
user = "root"
|
||||
pass = "123456"
|
||||
name = "test"
|
||||
type = "mysql"
|
||||
role = "master"
|
||||
charset = "utf8"
|
||||
priority = "1"
|
||||
[[database.default]]
|
||||
host = "127.0.0.1"
|
||||
port = "3306"
|
||||
user = "root"
|
||||
pass = "123456"
|
||||
name = "test"
|
||||
type = "mysql"
|
||||
role = "master"
|
||||
charset = "utf8"
|
||||
priority = "1"
|
||||
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<config>
|
||||
<!-- 模板引擎目录 -->
|
||||
<viewpath>/home/www/templates/</viewpath>
|
||||
<!-- MySQL数据库配置 -->
|
||||
<database>
|
||||
<default>
|
||||
<host>127.0.0.1</host>
|
||||
|
||||
@ -1,20 +1,25 @@
|
||||
# 模板引擎目录
|
||||
viewpath: /home/www/templates/
|
||||
# MySQL数据库配置
|
||||
database:
|
||||
default:
|
||||
- host: 127.0.0.1
|
||||
port: 3306
|
||||
user: root
|
||||
pass: 123456
|
||||
name: test
|
||||
type: mysql
|
||||
role: master
|
||||
priority: 1
|
||||
- host: 127.0.0.1
|
||||
port: 3306
|
||||
user: root
|
||||
pass: 123456
|
||||
name: test
|
||||
type: mysql
|
||||
role: master
|
||||
priority: 1
|
||||
default:
|
||||
- host: 127.0.0.1
|
||||
port: 3306
|
||||
user: root
|
||||
pass: 123456
|
||||
name: test
|
||||
type: mysql
|
||||
role: master
|
||||
charset: utf-8
|
||||
priority: 1
|
||||
- host: 127.0.0.1
|
||||
port: 3306
|
||||
user: root
|
||||
pass: 123456
|
||||
name: test
|
||||
type: mysql
|
||||
role: master
|
||||
charset: utf-8
|
||||
priority: 1
|
||||
|
||||
|
||||
|
||||
@ -7,6 +7,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
j, _ := gjson.Load("/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/geg/frame/config.json")
|
||||
c, _ := j.ToToml()
|
||||
fmt.Println(string(c))
|
||||
return
|
||||
data :=
|
||||
`{
|
||||
"users" : {
|
||||
@ -17,12 +21,14 @@ func main() {
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
j.Set("users.count", 1)
|
||||
//j.Set("users.count", 1)
|
||||
j.Set("users.list", []string{"John", "小明"})
|
||||
j.Set("users.0", "a")
|
||||
fmt.Println(j.Get("users.count"))
|
||||
fmt.Println(j.Get("users.count"))
|
||||
//fmt.Println(j.Get("users.list"))
|
||||
fmt.Println(j.Set("users.list.10", []string{"John", "小明10"}))
|
||||
fmt.Println(j.Set("users.list.9", []string{"John", "小明9"}))
|
||||
j.Set("users", "a")
|
||||
//fmt.Println(j.Get("users.count"))
|
||||
//fmt.Println(j.Get("users.count"))
|
||||
fmt.Println(j.Get("users.list.10"))
|
||||
c, _ := j.ToJson()
|
||||
fmt.Println(string(c))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user