gjson模块支持内容修改特性,开发中

This commit is contained in:
John
2018-01-22 17:55:12 +08:00
parent 79fcfa728b
commit a0f2916c55
5 changed files with 236 additions and 126 deletions

View File

@ -21,13 +21,9 @@ import (
// json解析结果存放数组
type Json struct {
// 注意这是一个指针
value *interface{}
p *interface{} // 注意这是一个指针
}
// 一个json变量
type JsonVar interface{}
// 编码go变量为json字符串并返回json字符串指针
func Encode (v interface{}) ([]byte, error) {
return json.Marshal(v)
@ -106,8 +102,8 @@ func NewJson(v *interface{}) *Json {
// 将指定的json内容转换为指定结构返回查找失败或者转换失败目标对象转换为nil
// 注意第二个参数需要给的是变量地址
func (p *Json) GetToVar(pattern string, v interface{}) error {
r := p.Get(pattern)
func (j *Json) GetToVar(pattern string, v interface{}) error {
r := j.Get(pattern)
if r != nil {
if t, err := Encode(r); err == nil {
return DecodeTo(t, v)
@ -122,8 +118,8 @@ func (p *Json) GetToVar(pattern string, v interface{}) error {
// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与json类型不匹配那么将会返回nil
func (p *Json) GetMap(pattern string) map[string]interface{} {
result := p.Get(pattern)
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
@ -133,8 +129,8 @@ func (p *Json) GetMap(pattern string) map[string]interface{} {
}
// 将检索值转换为Json对象指针返回
func (p *Json) GetJson(pattern string) *Json {
result := p.Get(pattern)
func (j *Json) GetJson(pattern string) *Json {
result := j.Get(pattern)
if result != nil {
return &Json{&result}
}
@ -143,8 +139,8 @@ func (p *Json) GetJson(pattern string) *Json {
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与json类型不匹配那么将会返回nil
func (p *Json) GetArray(pattern string) []interface{} {
result := p.Get(pattern)
func (j *Json) GetArray(pattern string) []interface{} {
result := j.Get(pattern)
if result != nil {
if r, ok := result.([]interface{}); ok {
return r
@ -154,114 +150,208 @@ func (p *Json) GetArray(pattern string) []interface{} {
}
// 返回指定json中的string
func (p *Json) GetString(pattern string) string {
return gconv.String(p.Get(pattern))
func (j *Json) GetString(pattern string) string {
return gconv.String(j.Get(pattern))
}
// 返回指定json中的bool(false:"", 0, false, off)
func (p *Json) GetBool(pattern string) bool {
return gconv.Bool(p.Get(pattern))
func (j *Json) GetBool(pattern string) bool {
return gconv.Bool(j.Get(pattern))
}
func (p *Json) GetInt(pattern string) int {
return gconv.Int(p.Get(pattern))
func (j *Json) GetInt(pattern string) int {
return gconv.Int(j.Get(pattern))
}
func (p *Json) GetUint(pattern string) uint {
return gconv.Uint(p.Get(pattern))
func (j *Json) GetUint(pattern string) uint {
return gconv.Uint(j.Get(pattern))
}
func (p *Json) GetFloat32(pattern string) float32 {
return gconv.Float32(p.Get(pattern))
func (j *Json) GetFloat32(pattern string) float32 {
return gconv.Float32(j.Get(pattern))
}
func (p *Json) GetFloat64(pattern string) float64 {
return gconv.Float64(p.Get(pattern))
func (j *Json) GetFloat64(pattern string) float64 {
return gconv.Float64(j.Get(pattern))
}
// 根据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
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
} 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
}
case []interface{}:
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 {
(*pointer).([]interface{})[n] = value
} else {
// 注意这里产生了临时变量和赋值拷贝
array := (*pointer).([]interface{})
array = append(array, value)
*pointer = array
}
break
} else {
pointer = &(*pointer).([]interface{})[n]
}
} else {
return err
}
}
}
}
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
} else {
if len((*j.p).([]interface{})) > n {
(*j.p).([]interface{})[n] = value
} else {
// 注意这里产生了临时变量和赋值拷贝
array := (*j.p).([]interface{})
array = append(array, value)
*j.p = array
}
}
}
}
return nil
}
// 根据约定字符串方式访问json解析数据参数形如 "items.name.first", "list.0"
// 返回的结果类型的interface{},因此需要自己做类型转换
// 如果找不到对应节点的数据返回nil
func (p *Json) Get(pattern string) interface{} {
var result interface{}
pointer := p.value
array := strings.Split(pattern, ".")
length := len(array)
for i:= 0; i < length; i++ {
switch (*pointer).(type) {
case map[string]interface{}:
if v, ok := (*pointer).(map[string]interface{})[array[i]]; ok {
if i == length - 1 {
result = v
} else {
pointer = &v
}
} else {
return nil
}
case []interface{}:
if isNumeric(array[i]) {
n, err := strconv.Atoi(array[i])
if err == nil && len((*pointer).([]interface{})) > n {
if i == length - 1 {
result = (*pointer).([]interface{})[n]
break;
} else {
pointer = &(*pointer).([]interface{})[n]
}
}
} else {
return nil
}
default:
return 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
}
}
return result
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
}
// 转换为map[string]interface{}类型,如果转换失败返回nil
func (p *Json) ToMap() map[string]interface{} {
switch (*(p.value)).(type) {
func (j *Json) ToMap() map[string]interface{} {
switch (*(j.p)).(type) {
case map[string]interface{}:
return (*(p.value)).(map[string]interface{})
return (*(j.p)).(map[string]interface{})
default:
return nil
}
}
// 转换为[]interface{}类型,如果转换失败返回nil
func (p *Json) ToArray() []interface{} {
switch (*(p.value)).(type) {
func (j *Json) ToArray() []interface{} {
switch (*(j.p)).(type) {
case []interface{}:
return (*(p.value)).([]interface{})
return (*(j.p)).([]interface{})
default:
return nil
}
}
func (p *Json) ToXml(rootTag...string) ([]byte, error) {
return gxml.Encode(p.ToMap(), rootTag...)
func (j *Json) ToXml(rootTag...string) ([]byte, error) {
return gxml.Encode(j.ToMap(), rootTag...)
}
func (p *Json) ToXmlIndent(rootTag...string) ([]byte, error) {
return gxml.EncodeWithIndent(p.ToMap(), rootTag...)
func (j *Json) ToXmlIndent(rootTag...string) ([]byte, error) {
return gxml.EncodeWithIndent(j.ToMap(), rootTag...)
}
func (p *Json) ToJson() ([]byte, error) {
return Encode(*(p.value))
func (j *Json) ToJson() ([]byte, error) {
return Encode(*(j.p))
}
func (p *Json) ToJsonIndent() ([]byte, error) {
return json.MarshalIndent(*(p.value), "", "\t")
func (j *Json) ToJsonIndent() ([]byte, error) {
return json.MarshalIndent(*(j.p), "", "\t")
}
func (p *Json) ToYaml() ([]byte, error) {
return gyaml.Encode(*(p.value))
func (j *Json) ToYaml() ([]byte, error) {
return gyaml.Encode(*(j.p))
}
func (p *Json) ToToml() ([]byte, error) {
return gtoml.Encode(*(p.value))
func (j *Json) ToToml() ([]byte, error) {
return gtoml.Encode(*(j.p))
}
// 判断所给字符串是否为数字

View File

@ -6,20 +6,42 @@ import (
"gitee.com/johng/gf/g/encoding/gjson"
)
func main() {
data := `{
"users" : {
"count" : 100,
"list" : [
{"name" : "小明", "score" : 60},
{"name" : "John", "score" : 99.5}
]
func getByPattern() {
data :=
`{
"users" : {
"count" : 100,
"list" : [
{"name" : "小明", "score" : 60},
{"name" : "John", "score" : 99.5}
]
}
}`
}`
j, err := gjson.DecodeToJson([]byte(data))
if err != nil {
glog.Error(err)
} else {
fmt.Println("John Score:", j.GetFloat32("users.list.1.score"))
}
}
// 当键名存在"."号时,检索优先级:键名->层级,因此不会引起歧义
func testMultiDots() {
data :=
`{
"users" : {
"count" : 100
},
"users.count" : 101
}`
j, err := gjson.DecodeToJson([]byte(data))
if err != nil {
glog.Error(err)
} else {
fmt.Println("Users Count:", j.GetInt("users.count"))
}
}
func main() {
testMultiDots()
}

View File

@ -1,31 +0,0 @@
package main
import (
"testing"
"gitee.com/johng/gf/g/encoding/gjson"
"encoding/json"
"log"
)
// go test json_test.go -bench=".*"
var data = `[{"CityId":1, "CityName":"北京", "ProvinceId":1, "CityOrder":1}, {"CityId":5, "CityName":"成都", "ProvinceId":27, "CityOrder":1}]`
func BenchmarkJsonDecode(b *testing.B) {
b.N = 1000000
for i := 0; i < b.N; i++ {
gjson.Decode(data)
}
}
func BenchmarkJsonDecodeByUnmarshal(b *testing.B) {
b.N = 1000000
for i := 0; i < b.N; i++ {
var citys interface{}
if err := json.Unmarshal([]byte(data), &citys); err != nil {
log.Fatalf("JSON unmarshaling failed: %s", err)
}
//fmt.Println(citys)
}
}

View File

@ -2,16 +2,28 @@ package main
import (
"fmt"
"gitee.com/johng/gf/g/encoding/gjson"
"gitee.com/johng/gf/g/os/glog"
)
func main() {
c1 := make(chan int, 2)
c2 := make(chan int, 5)
c1 <- 1
c1 <- 2
c2 = c1
c2 <- 3
fmt.Println(<-c2)
fmt.Println(<-c2)
fmt.Println(<-c2)
data :=
`{
"users" : {
"count" : 100
}
}`
j, err := gjson.DecodeToJson([]byte(data))
if err != nil {
glog.Error(err)
} else {
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"))
c, _ := j.ToJson()
fmt.Println(string(c))
}
}

17
geg/other/test2.go Normal file
View File

@ -0,0 +1,17 @@
package main
import (
"fmt"
)
func main() {
//var v interface{}
m := map[string]int {
"age" : 18,
}
//v = m
p := &m
(*p)["age"] = 16
//fmt.Println(v)
fmt.Println(m)
}