Skip to content

Instantly share code, notes, and snippets.

@mattn
Created Apr 24, 2013
Embed
What would you like to do?
package main
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
)
var s = `
{
"foo": {
"bar": [
{
"baz": "bbb",
"noo": 3
},
{
"maz": true,
"moo": ["foo", "bar"]
}
],
"boo": {
"bag": "ddd",
"bug": "ccc"
}
}
}
`
var re = regexp.MustCompile("^([^0-9\\s\\[][^\\s\\[]*)?(\\[[0-9]+\\])?$")
func jsonScan(b []byte, jp string, t interface{}) (err error) {
var v interface{}
err = json.Unmarshal([]byte(s), &v)
if err != nil {
return err
}
if jp == "" {
return errors.New("invalid path")
}
var ok bool
for _, token := range strings.Split(jp, "/") {
sl := re.FindAllStringSubmatch(token, -1)
if len(sl) == 0 {
return errors.New("invalid path")
}
ss := sl[0]
if ss[1] != "" {
if v, ok = v.(map[string]interface{})[ss[1]]; !ok {
return errors.New("invalid path: " + ss[1])
}
}
if ss[2] != "" {
i, err := strconv.Atoi(ss[2][1 : len(ss[2])-1])
if err != nil {
return errors.New("invalid path: " + ss[2])
}
var vl []interface{}
if vl, ok = v.([]interface{}); !ok {
return errors.New("invalid path: " + ss[2])
}
if i < 0 || i > len(vl)-1 {
return errors.New("invalid path: " + ss[2])
}
v = vl[i]
}
}
rt := reflect.ValueOf(t).Elem()
rv := reflect.ValueOf(v)
defer func() {
if errstr := recover(); errstr != nil {
err = errors.New(errstr.(string))
}
}()
rt.Set(rv)
return nil
}
func main() {
var t1 string
var err error
err = jsonScan([]byte(s), "/foo/bar[0]/baz", &t1)
if err == nil {
fmt.Println(t1)
} else {
fmt.Println(err.Error())
}
var t2 float64
err = jsonScan([]byte(s), "/foo/bar[0]/noo", &t2)
if err == nil {
fmt.Println(t2)
} else {
fmt.Println(err.Error())
}
var t3 bool
err = jsonScan([]byte(s), "/foo/bar[1]/maz", &t3)
if err == nil {
fmt.Println(t3)
} else {
fmt.Println(err.Error())
}
var t4 []interface{}
err = jsonScan([]byte(s), "/foo/bar[1]/moo", &t4)
if err == nil {
fmt.Println(t4)
} else {
fmt.Println(err.Error())
}
var t5 map[string]interface{}
err = jsonScan([]byte(s), "/foo/boo", &t5)
if err == nil {
fmt.Println(t5)
} else {
fmt.Println(err.Error())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment