初步完善gjson功能,新增gparser包,用于编码/解析json,xml,yaml,toml数据格式内容

This commit is contained in:
John
2018-01-23 15:02:42 +08:00
parent a0f2916c55
commit 84ddf73cb4
9 changed files with 333 additions and 54 deletions

View File

@ -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))
}

View 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()
}

View File

@ -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 {

View File

@ -17,7 +17,7 @@ import (
)
const (
gDEFAULT_CONFIG_FILE = "config.json" // 默认的配置管理文件名称
gDEFAULT_CONFIG_FILE = "config.yml" // 默认的配置管理文件名称
)
// 配置管理对象

View File

@ -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
View 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"

View File

@ -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>

View File

@ -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

View File

@ -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))
}