Skip to content

Instantly share code, notes, and snippets.

@FZambia
Forked from m0sth8/jsonhelper.go
Created March 12, 2014 05:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FZambia/9501653 to your computer and use it in GitHub Desktop.
Save FZambia/9501653 to your computer and use it in GitHub Desktop.
// Example
package main;
import (
"jsonhelper"
"fmt"
)
func main(){
jsonValue := []interface {}{
map[string]interface {}{"one" : map[string]interface{}{"two" : 1}},
[]interface{}{"one", "two", "three"},
map[string]interface {}{"one": []interface{}{1, 2 , 3}},
}
value, err = getValue("/[2]/one[0]", jsonValue)
fmt.Println(value) // Output: 1
}
package jsonhelper
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"regexp"
)
var (
itemMapRe = regexp.MustCompile("^[^0-9\\s\\[][^\\s\\[]*")
itemArrayRe = regexp.MustCompile("\\[[0-9]+\\]")
)
func LoadJson(jsonStr string) (interface{}, error) {
var jsonValue interface{}
err := json.Unmarshal([]byte(jsonStr), &jsonValue)
return jsonValue, err
}
func GetString(path string, jsonValue interface{}) (string, error) {
var result string
err := GetValue(path, jsonValue, &result)
return result, err
}
func GetInt(path string, jsonValue interface{}) (int, error) {
var result int
err := GetValue(path, jsonValue, &result)
return result, err
}
func GetFloat(path string, jsonValue interface{}) (float64, error) {
var result float64
err := GetValue(path, jsonValue, &result)
return result, err
}
func GetSlice(path string, jsonValue interface {}) (result []interface{}, err error) {
err = GetValue(path, jsonValue, &result)
return
}
func GetMap(path string, jsonValue interface {}) (result map[string]interface {}, err error) {
err = GetValue(path, jsonValue, &result)
return
}
func GetValue(path string, jsonValue interface{}, result interface{}) error {
rv := reflect.ValueOf(result)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return errors.New(fmt.Sprintf("The value %#v is not a pointer, you must call GetValue with a pointer as an argument", result))
}
value, err := getValue(path, jsonValue)
if err != nil {
return err
}
if reflect.TypeOf(result) != reflect.PtrTo(reflect.TypeOf(value)) {
return errors.New(fmt.Sprintf("The value %#v is not %v but %v", value, reflect.TypeOf(result).Elem(), reflect.TypeOf(value)))
} else {
valueReflect := reflect.ValueOf(value)
reflect.ValueOf(result).Elem().Set(valueReflect)
}
return nil
}
func getValue(path string, jsonValue interface{}) (interface {}, error) {
var found bool
currentJsonValue := jsonValue
for _, pathElement := range(strings.Split(path, "/")) {
itemMapName := itemMapRe.FindString(pathElement)
if itemMapName != "" {
if mapValue, ok := currentJsonValue.(map[string]interface{}); ok {
if currentJsonValue, found = mapValue[itemMapName]; !found {
return nil, errors.New(fmt.Sprintf("Could not find element in path. The errorneous element is %v", pathElement))
}
} else {
return nil, errors.New(fmt.Sprintf("Could not find element in path. The errorneous element is %v", pathElement))
}
}
arrayIndexes := itemArrayRe.FindAllString(pathElement, -1)
for _, indexStr := range(arrayIndexes) {
if arrayIndex, err := strconv.Atoi(indexStr[1:len(indexStr)-1]); err != nil {
return nil, errors.New(fmt.Sprintf("Array index '%v' should be an int type", pathElement))
} else {
if arrayValue, ok := currentJsonValue.([]interface{}); ok {
if arrayIndex >= len(arrayValue) {
return nil, errors.New(fmt.Sprintf("Array index '%d' is out of range '%d'", arrayIndex, len(arrayValue)))
}
currentJsonValue = arrayValue[arrayIndex]
} else {
return nil, errors.New(fmt.Sprintf("Could not find element in path. The errorneous element is %v", pathElement))
}
}
}
}
return currentJsonValue, nil
}
package jsonhelper
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetValue(t *testing.T) {
jsonValue := map[string]interface{}{"one" : map[string]interface{}{"two" : 1}}
value, err := getValue("/one", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, map[string]interface{}{"two" : 1})
}
value, err = getValue("/one/two", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, 1)
}
value, err = getValue("/one/two/three", jsonValue)
assert.NotNil(t, err)
}
func TestGetArrayValue(t *testing.T) {
jsonValue := []interface {}{
map[string]interface {}{"one" : map[string]interface{}{"two" : 1}},
[]interface{}{"one", "two", "three"},
map[string]interface {}{"one": []interface{}{1, 2 , 3}},
}
value, err := getValue("[0]/one", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, map[string]interface{}{"two" : 1})
}
value, err = getValue("/[1][0]", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, "one")
}
value, err = getValue("/[1][2]", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, "three")
}
value, err = getValue("/[1][3]", jsonValue)
assert.NotNil(t, err)
value, err = getValue("/[2]/one[0]", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, 1)
}
value, err = getValue("/[2]/two[0]", jsonValue)
assert.NotNil(t, err)
value, err = getValue("/one/one", jsonValue)
assert.NotNil(t, err)
value, err = getValue("/[]/one", jsonValue)
assert.NotNil(t, err)
}
func TestGet(t *testing.T) {
jsonValue := map[string]interface{}{
"one" : map[string]interface{}{ "value" : "testString" },
"two" : 2,
"three" : 1.1,
"four" : []int{1, 2},
"five": []interface {}{"zero", 1, 2.2, []int{4, 5}},
}
var value string
err := GetValue("/one/value", jsonValue, &value)
if assert.Nil(t, err) {
assert.Equal(t, value, "testString")
}
err = GetValue("/five/[0]", jsonValue, &value)
if assert.Nil(t, err) {
assert.Equal(t, value, "zero")
}
var valueInt int
err = GetValue("/two", jsonValue, &valueInt)
if assert.Nil(t, err) {
assert.Equal(t, valueInt, 2)
}
err = GetValue("/five[1]", jsonValue, &valueInt)
if assert.Nil(t, err) {
assert.Equal(t, valueInt, 1)
}
var valueFloat float64
err = GetValue("/three", jsonValue, &valueFloat)
if assert.Nil(t, err) {
assert.Equal(t, valueFloat, 1.1)
}
err = GetValue("/five[2]", jsonValue, &valueFloat)
if assert.Nil(t, err) {
assert.Equal(t, valueFloat, 2.2)
}
var valueArray []int
err = GetValue("/four", jsonValue, &valueArray)
if assert.Nil(t, err) {
assert.Equal(t, valueArray, []int{1, 2})
}
err = GetValue("/five[3]", jsonValue, &valueArray)
if assert.Nil(t, err) {
assert.Equal(t, valueArray, []int{4, 5})
}
//passing value not pointer
err = GetValue("four", jsonValue, valueArray)
assert.NotNil(t, err)
}
func TestGetByType(t *testing.T) {
var (
err error
)
jsonValue := map[string]interface{}{
"one" : map[string]interface{}{ "value" : "testString" },
"two" : 2,
"three" : 1.1,
"four" : []interface{} {1, 2},
"five": []interface {}{"zero", 1, 2.2, []int{4, 5}},
}
var value string
value, err = GetString("/one/value", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, "testString")
}
value, err = GetString("/five/[0]", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, value, "zero")
}
var valueInt int
valueInt, err = GetInt("/two", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, valueInt, 2)
}
valueInt, err = GetInt("/five[1]", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, valueInt, 1)
}
var valueFloat float64
valueFloat, err = GetFloat("/three", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, valueFloat, 1.1)
}
valueFloat, err = GetFloat("/five[2]", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, valueFloat, 2.2)
}
var valueSlice []interface{}
valueSlice, err = GetSlice("/four", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, valueSlice, []interface{}{1, 2})
}
valueSlice, err = GetSlice("/five", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, len(valueSlice), 4)
assert.Equal(t, valueSlice[0], "zero")
}
var valueMap map[string]interface{}
valueMap, err = GetMap("/one", jsonValue)
if assert.Nil(t, err) {
assert.Equal(t, valueMap, map[string]interface{}{ "value" : "testString" })
}
}
func TestLoadJson(t *testing.T) {
jsonValue, err := LoadJson("{\"uk\" : {\"one\": \"one\", \"two\": 2}}")
if assert.Nil(t, err) {
assert.Equal(t, jsonValue, map[string]interface {}{"uk":map[string]interface{}{"one":"one", "two":2}})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment