{"id":30659899,"url":"https://github.com/toukii/jsnm","last_synced_at":"2025-10-05T22:16:56.433Z","repository":{"id":77986204,"uuid":"46701150","full_name":"toukii/jsnm","owner":"toukii","description":"json mapping for map[string]interface{}","archived":false,"fork":false,"pushed_at":"2025-08-28T12:39:43.000Z","size":49,"stargazers_count":11,"open_issues_count":2,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-28T19:52:52.804Z","etag":null,"topics":["golang","json","json-map","json-parser"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/toukii.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-11-23T06:31:05.000Z","updated_at":"2025-08-28T12:30:50.000Z","dependencies_parsed_at":"2025-08-28T14:25:51.496Z","dependency_job_id":"75d782c6-7b13-4720-9e40-da45bf0d00c4","html_url":"https://github.com/toukii/jsnm","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/toukii/jsnm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toukii%2Fjsnm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toukii%2Fjsnm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toukii%2Fjsnm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toukii%2Fjsnm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/toukii","download_url":"https://codeload.github.com/toukii/jsnm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toukii%2Fjsnm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272983448,"owners_count":25026099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","json","json-map","json-parser"],"created_at":"2025-08-31T13:08:11.301Z","updated_at":"2025-10-05T22:16:51.381Z","avatar_url":"https://github.com/toukii.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"#\t[jsnm][1]\n\n---------------------\n\n\n__json mapping for map[string]interface{}__\n\n提供缓存的json解析器，初衷是提高重复解析json速度。\n\n\n## 用法\n\n方法有：__Get PathGet Arr ArrLoc ArrLocs ArrPath__，为了对比，提供了不带缓存的方法：__NCGet__.\n\n - 带有数组的，要用ArrPath;\n\n - 无数组形式可以用Get或PathGet;\n\n - 若不使用缓存，用NCGet,性能会低。\n\n\n1. 定义结构体如下：\n\n```go\ntype User struct {\n\tName    string\n\tAge     byte\n\tLoc     []string\n\tFriends map[string]*User\n}\n```\n\n2. 数据如下：\n\n```json\n{\n\t\"Name\": \"foo\",\n\t\"Age\": 21,\n\t\"Friends\": {\n\t\t\"bar\": {\n\t\t\t\"Name\": \"bar\",\n\t\t\t\"Age\": 22,\n\t\t\t\"Friends\": {\n\t\t\t\t\"bar\": null\n\t\t\t},\n\t\t\t\"Loc\": [\n\t\t\t\t\"shanghai\",\n\t\t\t\t\"jiaxing\"\n\t\t\t]\n\t\t},\n\t\t\"kaa\": null\n\t},\n\t\"Loc\": [\n\t\t\"beijing\",\n\t\t\"tianjin\"\n\t]\n}\n```\n\n3. 用法\n\n```\njs.Get(\"Friends\").Get(\"bar\").Get(\"Loc\").ArrLoc(0).String()\njs.PathGet(\"Friends\",\"bar\").Get(\"Loc\").Arr[0].String()\njs.Get(\"Friends\").PathGet(\"bar\",\"Loc\").ArrLoc(0).String()\njs.PathGet(\"Friends\",\"bar\",\"Loc\").Arr[0].String()\njs.ArrPath(\"Friends\",\"bar\",\"Loc\",0).String()\n```\n\n再如：\n\n```\n[\n    [\n        [\n            [\n                \"a\"\n            ]\n        ]\n    ]\n]\n```\n\n获取`a`的方式：\n\n```\njs.ArrLocs(0,0,0,0).String()\njs.ArrLocs(0,0).ArrLoc(0).Arr[0].String()\njs.Arr[0].ArrLocs(0,0).ArrLoc(0).String()\njs.ArrLoc(0).Arr[0].ArrLocs(0,0).String()\n```\n\n##\t数据结构设计\n\n```go\ntype Jsnm struct {\n\traw   RawData\n\tdata  MapData\n\tarr_data []*Jsnm\n\tcache map[string]*Jsnm\n}\n\ntype RawData struct {\n\traw interface{}\n}\n\ntype MapData map[string]interface{}\n```\n\n**RawData是原始数据；MapData是可以转换为map[string]interface{}的RawData；arr_data缓存数组；cache是缓存数据，有重合路径时，可以提高访问速度。**\n\n##\t核心函数\n\n**Get**\n\n```go\n// Cache PathGet\nfunc (j *Jsnm) PathGet(path ...string) *Jsnm {\n\tif j == nil || len(path) \u003c= 0 {\n\t\treturn j\n\t}\n\tjm := j\n\tvar cache_jm *Jsnm\n\tvar exist bool\n\tvar sub_data interface{}\n\tfor _, subpath := range path {\n\t\tif jm.cache == nil {\n\t\t\tjm.cache = make(map[string]*Jsnm)\n\t\t} else {\n\t\t\tif cache_jm, exist = jm.cache[subpath]; exist {\n\t\t\t\tjm = cache_jm\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif jm.map_data == nil {\n\t\t\tjm.map_data = make(MapData)\n\t\t\tif map_data, ok := jm.raw_data.(map[string]interface{}); ok {\n\t\t\t\tjm.map_data = map_data\n\t\t\t} else {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tsub_data, exist = jm.map_data[subpath]\n\t\tif !exist {\n\t\t\treturn nil\n\t\t}\n\t\tsub_jm := NewJsnm(sub_data)\n\t\tjm.cache[subpath] = sub_jm\n\t\tjm = sub_jm\n\t}\n\treturn jm\n}\n\n// Cache Get\nfunc (j *Jsnm) Get(path string) *Jsnm {\n\tif j==nil {\n\t\treturn nil\n\t}\n\t// first step: get data from cache\n\tif nil == j.cache {\n\t\tj.cache = make(map[string]*Jsnm)\n\t} else {\n\t\tif cache_data, ok := j.cache[path]; ok {\n\t\t\treturn cache_data\n\t\t}\n\t}\n\t// second step: get data from mapdata\n\tif j.map_data == nil {\n\t\tif map_data, ok := j.raw_data.(map[string]interface{}); ok {\n\t\t\tj.map_data = map_data\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t}\n\tcur, ok := j.map_data[path]\n\tif !ok {\n\t\treturn nil\n\t}\n\t// third step: cache the data\n\twill_cache_data := NewJsnm(cur)\n\tj.cache[path] = will_cache_data\n\treturn will_cache_data\n}\n```\n\n-------------------------------\n\n**Arr**\n\n```go\n// Cache Arr\nfunc (j *Jsnm) Arr() []*Jsnm {\n\tif j == nil {\n\t\treturn nil\n\t}\n\tif j.arr_data != nil {\n\t\treturn j.arr_data\n\t}\n\tarr, ok := (j.raw_data).([]interface{})\n\tif !ok {\n\t\treturn nil\n\t}\n\tret := make([]*Jsnm, 0, len(arr))\n\tfor _, vry := range arr {\n\t\tret = append(ret, NewJsnm(vry))\n\t}\n\tj.arr_data = ret\n\treturn ret\n}\n\n// Cache ArrLocs\nfunc (j *Jsnm) ArrLocs(locs ...int) *Jsnm {\n\tif len(locs)\u003c=0 {\n\t\treturn nil\n\t}\n\tsubarr:= j.ArrLoc(locs[0])\n\tl:=len(locs)\n\tfor i := 1; i \u003c l; i++ {\n\t\tif subarr==nil {\n\t\t\t return nil\n\t\t}\n\t\tsubarr = subarr.ArrLoc(locs[i])\n\t}\n\treturn subarr\n}\n\n// Cache ArrLoc i\nfunc (j *Jsnm) ArrLoc(i int) *Jsnm {\n\tif j == nil {\n\t\treturn nil\n\t}\n\tif nil != j.arr_data {\n\t\tif i \u003e= len(j.arr_data) {\n\t\t\treturn nil\n\t\t}\n\t\tif j.arr_data[i] != nil {\n\t\t\treturn j.arr_data[i]\n\t\t}\n\t}\n\tarr, ok := (j.raw_data).([]interface{})\n\tif !ok {\n\t\treturn nil\n\t}\n\tarr_cache := make([]*Jsnm, len(arr))\n\tj.arr_data = arr_cache\n\tj.arr_data[i] = NewJsnm(arr[i])\n\tif i \u003e= len(arr) {\n\t\treturn nil\n\t}\n\treturn j.arr_data[i]\n}\n\n// Cache ArrPath path\nfunc (j *Jsnm) ArrPath(path ...interface{}) *Jsnm {\n\tif len(path) \u003c= 0 {\n\t\treturn j\n\t}\n\tswitch reflect.TypeOf(path[0]).Kind() {\n\tcase reflect.String:\n\t\treturn j.Get(path[0].(string)).ArrPath(path[1:]...)\n\tcase reflect.Int:\n\t\treturn j.ArrLoc(path[0].(int)).ArrPath(path[1:]...)\n\t}\n\treturn nil\n}\n```\n\n**具体的类型转换，可添加函数实现。**\n\n_Example_\n\n```go\nage := jm.Get(\"Friends\").Get(\"Age\").MustInt64()\nfmt.Println(age)\n```\n\n\n##\tBenchmark\n\n`go test -test.bench=\".*\"`\n\n![Test][3]\n\n可以看到，数组的解析要落后一些，原因在于对参数的检测。如果激进一点，可以将不检查参数，速度将提高至少4倍。\n\n [1]: https://github.com/toukii/jsnm \"jsnm\"\n [2]: http://7xku3c.com1.z0.glb.clouddn.com/jsnm-benchmark.png \"jsnm-bench\"\n [3]: http://7xku3c.com1.z0.glb.clouddn.com/benchmark-jsnm.png \"jsnm-bench\"","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoukii%2Fjsnm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoukii%2Fjsnm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoukii%2Fjsnm/lists"}