Skip to content

toukii/jsnm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

366af7b · May 28, 2019

History

44 Commits
Jan 26, 2018
May 6, 2017
Apr 19, 2018
Feb 24, 2018
May 28, 2019
Jun 19, 2018
May 28, 2019
Dec 19, 2017
Feb 24, 2018
May 28, 2019
Nov 24, 2015
Dec 19, 2017

Repository files navigation


json mapping for map[string]interface{}

提供缓存的json解析器,初衷是提高重复解析json速度。

用法

方法有:Get PathGet Arr ArrLoc ArrLocs ArrPath,为了对比,提供了不带缓存的方法:NCGet.

  • 带有数组的,要用ArrPath;

  • 无数组形式可以用Get或PathGet;

  • 若不使用缓存,用NCGet,性能会低。

  1. 定义结构体如下:
type User struct {
	Name    string
	Age     byte
	Loc     []string
	Friends map[string]*User
}
  1. 数据如下:
{
	"Name": "foo",
	"Age": 21,
	"Friends": {
		"bar": {
			"Name": "bar",
			"Age": 22,
			"Friends": {
				"bar": null
			},
			"Loc": [
				"shanghai",
				"jiaxing"
			]
		},
		"kaa": null
	},
	"Loc": [
		"beijing",
		"tianjin"
	]
}
  1. 用法
js.Get("Friends").Get("bar").Get("Loc").ArrLoc(0).String()
js.PathGet("Friends","bar").Get("Loc").Arr[0].String()
js.Get("Friends").PathGet("bar","Loc").ArrLoc(0).String()
js.PathGet("Friends","bar","Loc").Arr[0].String()
js.ArrPath("Friends","bar","Loc",0).String()

再如:

[
    [
        [
            [
                "a"
            ]
        ]
    ]
]

获取a的方式:

js.ArrLocs(0,0,0,0).String()
js.ArrLocs(0,0).ArrLoc(0).Arr[0].String()
js.Arr[0].ArrLocs(0,0).ArrLoc(0).String()
js.ArrLoc(0).Arr[0].ArrLocs(0,0).String()

数据结构设计

type Jsnm struct {
	raw   RawData
	data  MapData
	arr_data []*Jsnm
	cache map[string]*Jsnm
}

type RawData struct {
	raw interface{}
}

type MapData map[string]interface{}

RawData是原始数据;MapData是可以转换为map[string]interface{}的RawData;arr_data缓存数组;cache是缓存数据,有重合路径时,可以提高访问速度。

核心函数

Get

// Cache PathGet
func (j *Jsnm) PathGet(path ...string) *Jsnm {
	if j == nil || len(path) <= 0 {
		return j
	}
	jm := j
	var cache_jm *Jsnm
	var exist bool
	var sub_data interface{}
	for _, subpath := range path {
		if jm.cache == nil {
			jm.cache = make(map[string]*Jsnm)
		} else {
			if cache_jm, exist = jm.cache[subpath]; exist {
				jm = cache_jm
				continue
			}
		}
		if jm.map_data == nil {
			jm.map_data = make(MapData)
			if map_data, ok := jm.raw_data.(map[string]interface{}); ok {
				jm.map_data = map_data
			} else {
				return nil
			}
		}
		sub_data, exist = jm.map_data[subpath]
		if !exist {
			return nil
		}
		sub_jm := NewJsnm(sub_data)
		jm.cache[subpath] = sub_jm
		jm = sub_jm
	}
	return jm
}

// Cache Get
func (j *Jsnm) Get(path string) *Jsnm {
	if j==nil {
		return nil
	}
	// first step: get data from cache
	if nil == j.cache {
		j.cache = make(map[string]*Jsnm)
	} else {
		if cache_data, ok := j.cache[path]; ok {
			return cache_data
		}
	}
	// second step: get data from mapdata
	if j.map_data == nil {
		if map_data, ok := j.raw_data.(map[string]interface{}); ok {
			j.map_data = map_data
		} else {
			return nil
		}
	}
	cur, ok := j.map_data[path]
	if !ok {
		return nil
	}
	// third step: cache the data
	will_cache_data := NewJsnm(cur)
	j.cache[path] = will_cache_data
	return will_cache_data
}

Arr

// Cache Arr
func (j *Jsnm) Arr() []*Jsnm {
	if j == nil {
		return nil
	}
	if j.arr_data != nil {
		return j.arr_data
	}
	arr, ok := (j.raw_data).([]interface{})
	if !ok {
		return nil
	}
	ret := make([]*Jsnm, 0, len(arr))
	for _, vry := range arr {
		ret = append(ret, NewJsnm(vry))
	}
	j.arr_data = ret
	return ret
}

// Cache ArrLocs
func (j *Jsnm) ArrLocs(locs ...int) *Jsnm {
	if len(locs)<=0 {
		return nil
	}
	subarr:= j.ArrLoc(locs[0])
	l:=len(locs)
	for i := 1; i < l; i++ {
		if subarr==nil {
			 return nil
		}
		subarr = subarr.ArrLoc(locs[i])
	}
	return subarr
}

// Cache ArrLoc i
func (j *Jsnm) ArrLoc(i int) *Jsnm {
	if j == nil {
		return nil
	}
	if nil != j.arr_data {
		if i >= len(j.arr_data) {
			return nil
		}
		if j.arr_data[i] != nil {
			return j.arr_data[i]
		}
	}
	arr, ok := (j.raw_data).([]interface{})
	if !ok {
		return nil
	}
	arr_cache := make([]*Jsnm, len(arr))
	j.arr_data = arr_cache
	j.arr_data[i] = NewJsnm(arr[i])
	if i >= len(arr) {
		return nil
	}
	return j.arr_data[i]
}

// Cache ArrPath path
func (j *Jsnm) ArrPath(path ...interface{}) *Jsnm {
	if len(path) <= 0 {
		return j
	}
	switch reflect.TypeOf(path[0]).Kind() {
	case reflect.String:
		return j.Get(path[0].(string)).ArrPath(path[1:]...)
	case reflect.Int:
		return j.ArrLoc(path[0].(int)).ArrPath(path[1:]...)
	}
	return nil
}

具体的类型转换,可添加函数实现。

Example

age := jm.Get("Friends").Get("Age").MustInt64()
fmt.Println(age)

Benchmark

go test -test.bench=".*"

Test

可以看到,数组的解析要落后一些,原因在于对参数的检测。如果激进一点,可以将不检查参数,速度将提高至少4倍。

About

json mapping for map[string]interface{}

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages