package jaeson import ( "errors" "sort" "strconv" "strings" ) var ( JSON_VAL_TYPE_STRING = "str" JSON_VAL_TYPE_INT = "int" JSON_VAL_TYPE_FLOAT = "float" JSON_VAL_TYPE_BOOL = "jsbln" JSON_VAL_TYPE_OBJECT = "jsobj" JSON_VAL_TYPE_ARRAY = "jsarr" ) type JSONObject struct { ms map[string]string mo map[string]*JSONObject marr map[string]*JSONArray mn map[string]int mbln map[string]bool mflt64 map[string]float64 //contains all valid keys mAllkeys map[string]string ctms int ctmo int ctmarr int ctmn int ctmbln int ctmflt64 int hasVal bool //isSorted bool } func NewJSONObject() *JSONObject { jsObj := new(JSONObject) jsObj.Init() return jsObj } func NewJSONArray() *JSONArray { jsArr := new(JSONArray) jsArr.Init() return jsArr } func (v *JSONObject) Init() { v.ctms = 0 v.ctmo = 0 v.ctmarr = 0 v.ctmn = 0 v.ctmbln = 0 v.ctmflt64 = 0 v.ms = make(map[string]string, 0) v.mo = make(map[string]*JSONObject, 0) v.marr = make(map[string]*JSONArray, 0) v.mn = make(map[string]int, 0) v.mbln = make(map[string]bool, 0) v.mflt64 = make(map[string]float64, 0) v.hasVal = false //v.isSorted = false v.mAllkeys = make(map[string]string, 0) } func (v *JSONObject) KeySetSize() int { return v.ctms + v.ctmo + v.ctmarr + v.ctmn + v.ctmbln } func (v *JSONObject) Map() map[string]string { return v.mAllkeys } //---------- PUT ----------// func (v *JSONObject) PutString(key string, value string) { if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { v.RemoveJSONObject(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { v.RemoveJSONArray(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { v.RemoveInt(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { v.RemoveBool(key) } v.ms[key] = value v.ctms += 1 v.hasVal = true v.mAllkeys[key] = JSON_VAL_TYPE_STRING } func (v *JSONObject) PutJSONObject(key string, value *JSONObject) { if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { v.RemoveJSONArray(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { v.RemoveInt(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { v.RemoveString(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { v.RemoveBool(key) } v.mo[key] = value v.ctmo += 1 v.hasVal = true v.mAllkeys[key] = JSON_VAL_TYPE_OBJECT } func (v *JSONObject) PutJSONArray(key string, value *JSONArray) { if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { v.RemoveJSONObject(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { v.RemoveInt(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { v.RemoveString(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { v.RemoveBool(key) } v.marr[key] = value v.ctmarr += 1 v.hasVal = true v.mAllkeys[key] = JSON_VAL_TYPE_ARRAY } func (v *JSONObject) PutInt(key string, value int) { if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { v.RemoveJSONObject(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { v.RemoveJSONArray(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { v.RemoveString(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { v.RemoveBool(key) } v.mn[key] = value v.ctmn += 1 v.hasVal = true v.mAllkeys[key] = JSON_VAL_TYPE_INT } func (v *JSONObject) PutNumber(key string, value int) { v.PutInt(key, value) } func (v *JSONObject) PutBool(key string, value bool) { if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { v.RemoveJSONObject(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { v.RemoveJSONArray(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { v.RemoveString(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { v.RemoveInt(key) } v.mbln[key] = value v.ctmbln += 1 v.hasVal = true v.mAllkeys[key] = JSON_VAL_TYPE_BOOL } func (v *JSONObject) PutFloat(key string, value float64) { if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { v.RemoveJSONObject(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { v.RemoveJSONArray(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { v.RemoveString(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { v.RemoveInt(key) } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { v.RemoveBool(key) } v.mflt64[key] = value v.ctmflt64 += 1 v.hasVal = true v.mAllkeys[key] = JSON_VAL_TYPE_FLOAT } //---------- ACCUMULATE ----------// func (v *JSONObject) AccumulateJSONObject(key string, value *JSONObject) { jsArr, err := v.GetJSONArray(key) if err != nil { v.RemoveString(key) v.RemoveJSONObject(key) jsArr := NewJSONArray() jsArr.AddJSONObject(value) v.PutJSONArray(key, jsArr) } else { jsArr.AddJSONObject(value) } } //---------- GET ----------// func (v *JSONObject) GethasVal() bool { return v.hasVal } func (v *JSONObject) GetString(key string) (string, error) { if v.ctms > 0 { val, isContainsKey := v.ms[key] if isContainsKey { return val, nil }else{ _, err := v.GetValType(key) if err != nil { return "", err } else { return "", errors.New("value not a string") } } } else { _, err := v.GetValType(key) if err != nil { return "", err } else { return "", errors.New("value not an string") } } } func (v *JSONObject) GetJSONObject(key string) (*JSONObject, error) { if v.ctmo > 0 { val, isContainsKey := v.mo[key] if isContainsKey { return val, nil }else{ _, err := v.GetValType(key) if err != nil { return nil, err } else { return nil, errors.New("value not a JSONObject") } } } else { _, err := v.GetValType(key) if err != nil { return nil, err } else { return nil, errors.New("value not an JSONObject") } } } func (v *JSONObject) GetJSONArray(key string) (*JSONArray, error) { if v.ctmarr > 0 { val, isContainsKey := v.marr[key] if isContainsKey { return val, nil }else{ _, err := v.GetValType(key) if err != nil { return nil, err } else { return nil, errors.New("value not a JSONArray") } } } else { _, err := v.GetValType(key) if err != nil { return nil, err } else { return nil, errors.New("value not an JSONArray") } } } func (v *JSONObject) GetInt(key string) (int, error) { if v.ctmn > 0 { val, isContainsKey := v.mn[key] if isContainsKey { return val, nil }else{ _, err := v.GetValType(key) if err != nil { return -1, err } else { return -1, errors.New("value not an int") } } } else { _, err := v.GetValType(key) if err != nil { return -1, err } else { return -1, errors.New("value not an int") } } } func (v *JSONObject) GetNumber(key string) (int, error) { return v.GetInt(key) } func (v *JSONObject) GetBool(key string) (bool, error) { if v.ctmbln > 0 { val, isContainsKey := v.mbln[key] if isContainsKey { return val, nil }else{ _, err := v.GetValType(key) if err != nil { return false, err } else { return false, errors.New("value not a bool") } } } else { _, err := v.GetValType(key) if err != nil { return false, err } else { return false, errors.New("value not a bool") } } } func (v *JSONObject) GetFloat(key string) (float64, error) { if v.ctmflt64 > 0 { val, isContainsKey := v.mflt64[key] if isContainsKey { return val, nil }else{ _, err := v.GetValType(key) if err != nil { return -1, err } else { return -1, errors.New("value not a float") } } } else { _, err := v.GetValType(key) if err != nil { return -1, err } else { return -1, errors.New("value not a float") } } } func (v *JSONObject) GetValType(key string) (string, error) { if len(v.mAllkeys) > 0 { valType := v.mAllkeys[key] if len(valType) == 0 { return "", errors.New("key not found") } else { return valType, nil } } else { return "", errors.New("key not found") } } //---------- func REMOVE ----------// func (v *JSONObject) RemoveString(key string) (error) { if v.ctms > 0 { _, isContainsKey := v.ms[key] if isContainsKey { delete(v.ms, key) delete(v.mAllkeys, key) v.ctms = len(v.ms) }else{ return v.genericRemove(key, "string") } } else { return v.genericRemove(key, "string") } return nil } func (v *JSONObject) RemoveJSONObject(key string) (error) { if v.ctmo > 0 { _, isContainsKey := v.mo[key] if isContainsKey { delete(v.mo, key) delete(v.mAllkeys, key) v.ctmo = len(v.mo) }else{ return v.genericRemove(key, "JSONObject") } } else { return v.genericRemove(key, "JSONObject") } return nil } func (v *JSONObject) RemoveJSONArray(key string) (error) { if v.ctmarr > 0 { _, isContainsKey := v.marr[key] if isContainsKey { delete(v.marr, key) delete(v.mAllkeys, key) v.ctmarr = len(v.marr) }else{ return v.genericRemove(key, "JSONArray") } } else { return v.genericRemove(key, "JSONArray") } return nil } func (v *JSONObject) RemoveInt(key string) (error){ if v.ctmn > 0 { _, isContainsKey := v.mn[key] if isContainsKey { delete(v.mn, key) delete(v.mAllkeys, key) v.ctmn = len(v.mn) }else{ return v.genericRemove(key, "int") } } else { return v.genericRemove(key, "int") } return nil } func (v *JSONObject) RemoveBool(key string) (error){ if v.ctmbln > 0 { _, isContainsKey := v.mbln[key] if isContainsKey { delete(v.mbln, key) delete(v.mAllkeys, key) v.ctmbln = len(v.mbln) }else{ return v.genericRemove(key, "bool") } } else { return v.genericRemove(key, "bool") } return nil } func (v *JSONObject) RemoveFloat(key string) (error){ if v.ctmflt64 > 0 { _, isContainsKey := v.mflt64[key] if isContainsKey { delete(v.mflt64, key) delete(v.mAllkeys, key) v.ctmflt64 = len(v.mflt64) }else{ return v.genericRemove(key, "float") } } else { return v.genericRemove(key, "float") } return nil } func (v *JSONObject) RemoveAny(key string) (error){ _, isContainsKey := v.mAllkeys[key] if isContainsKey { valType, err := v.GetValType(key) if err != nil { return err } else { // delete appropriate collection switch valType { case JSON_VAL_TYPE_STRING: delete(v.ms, key) delete(v.mAllkeys, key) v.ctms = len(v.ms) case JSON_VAL_TYPE_BOOL: delete(v.mbln, key) delete(v.mAllkeys, key) v.ctmbln = len(v.mbln) case JSON_VAL_TYPE_INT: delete(v.mn, key) delete(v.mAllkeys, key) v.ctmn = len(v.mn) case JSON_VAL_TYPE_FLOAT: delete(v.mflt64, key) delete(v.mAllkeys, key) v.ctmflt64 = len(v.mflt64) case JSON_VAL_TYPE_OBJECT: delete(v.mo, key) delete(v.mAllkeys, key) v.ctmo = len(v.mo) case JSON_VAL_TYPE_ARRAY: delete(v.marr, key) delete(v.mAllkeys, key) v.ctmarr = len(v.marr) default: return errors.New("Invalid date type: " + valType) } } }else{ return errors.New("key not found") } return nil } func (v *JSONObject) genericRemove(key string, msgSuffx string) (error){ _, err := v.GetValType(key) if err != nil { return err } else { return errors.New("value not a "+msgSuffx) } } //---------- PRINT STRING----------// func (v *JSONObject) String() string { var out string = "{" if v.ctms > 0 { for keyms, _ := range v.ms { out += "\"" + keyms + "\":\"" + v.ms[keyms] + "\"," } } if v.ctmn > 0 { for keymn, _ := range v.mn { out += "\"" + keymn + "\":" + strconv.Itoa(v.mn[keymn]) + "," } } if v.ctmo > 0 { for keymo, _ := range v.mo { jsObj := v.mo[keymo] out += "\"" + keymo + "\":" + jsObj.String() + "," } } if v.ctmarr > 0 { for keymarr, _ := range v.marr { jsArr := v.marr[keymarr] out += "\"" + keymarr + "\":" + jsArr.String() + "," } } if v.ctmbln > 0 { for keymbln, _ := range v.mbln { if v.mbln[keymbln] { out += "\"" + keymbln + "\":true," }else{ out += "\"" + keymbln + "\":false," } } } if v.ctmflt64 > 0 { for keymflt64, _ := range v.mflt64 { out += "\"" + keymflt64 + "\":" + strconv.FormatFloat(v.mflt64[keymflt64], 'f', -1, 64 ) + "," } } if strings.HasSuffix(out, ",") { out = out[0 : len(out)-1] } out += "}" return out } func (v *JSONObject) StringJCS() string { var out string = "{" var keys []string keys = make([]string, 0, len(v.mAllkeys)) for k := range v.mAllkeys { keys = append(keys, k) } sort.Strings(keys) iLenKeys := len(keys) for idx := 0; idx < iLenKeys; idx++ { key := keys[idx] tmpVal := v.mAllkeys[key] switch tmpVal { case JSON_VAL_TYPE_OBJECT: jsObj := v.mo[key] out += "\"" + key + "\":\"" + jsObj.StringJCS() + "\"," case JSON_VAL_TYPE_ARRAY: jsArr := v.marr[key] out += "\"" + key + "\":" + jsArr.String() + "," case JSON_VAL_TYPE_BOOL: out += "\"" + key + "\":" + strconv.FormatBool(v.mbln[key]) + "," case JSON_VAL_TYPE_INT: out += "\"" + key + "\":" + strconv.Itoa(v.mn[key]) + "," case JSON_VAL_TYPE_FLOAT: out += "\"" + key + "\":" + strconv.FormatFloat(v.mflt64[key], 'f', -1, 64 ) + "," default: out += "\"" + key + "\":\"" + v.ms[key] + "\"," } } if strings.HasSuffix(out, ",") { out = out[0 : len(out)-1] } out += "}" return out }