mirror of https://github.com/tidwall/gjson.git
[FIX] Cleanup code
This commit is contained in:
parent
46c712f1ce
commit
901bd6381c
344
gjson.go
344
gjson.go
|
@ -210,34 +210,34 @@ func (t Result) ForEach(iterator func(key, value Result) bool) {
|
||||||
iterator(Result{}, t)
|
iterator(Result{}, t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
json := t.Raw
|
raw := t.Raw
|
||||||
var keys bool
|
var keys bool
|
||||||
var i int
|
var i int
|
||||||
var key, value Result
|
var key, value Result
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(raw); i++ {
|
||||||
if json[i] == '{' {
|
if raw[i] == '{' {
|
||||||
i++
|
i++
|
||||||
key.Type = String
|
key.Type = String
|
||||||
keys = true
|
keys = true
|
||||||
break
|
break
|
||||||
} else if json[i] == '[' {
|
} else if raw[i] == '[' {
|
||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if json[i] > ' ' {
|
if raw[i] > ' ' {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var str string
|
var str string
|
||||||
var vesc bool
|
var vesc bool
|
||||||
var ok bool
|
var ok bool
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(raw); i++ {
|
||||||
if keys {
|
if keys {
|
||||||
if json[i] != '"' {
|
if raw[i] != '"' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s := i
|
s := i
|
||||||
i, str, vesc, ok = parseString(json, i+1)
|
i, str, vesc, ok = parseString(raw, i+1)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -249,14 +249,14 @@ func (t Result) ForEach(iterator func(key, value Result) bool) {
|
||||||
key.Raw = str
|
key.Raw = str
|
||||||
key.Index = s
|
key.Index = s
|
||||||
}
|
}
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(raw); i++ {
|
||||||
if json[i] <= ' ' || json[i] == ',' || json[i] == ':' {
|
if raw[i] <= ' ' || raw[i] == ',' || raw[i] == ':' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s := i
|
s := i
|
||||||
i, value, ok = parseAny(json, i, true)
|
i, value, ok = parseAny(raw, i, true)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -291,29 +291,29 @@ type arrayOrMapResult struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
|
func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
|
||||||
var json = t.Raw
|
var raw = t.Raw
|
||||||
var i int
|
var i int
|
||||||
var value Result
|
var value Result
|
||||||
var count int
|
var count int
|
||||||
var key Result
|
var key Result
|
||||||
if vc == 0 {
|
if vc == 0 {
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(raw); i++ {
|
||||||
if json[i] == '{' || json[i] == '[' {
|
if raw[i] == '{' || raw[i] == '[' {
|
||||||
r.vc = json[i]
|
r.vc = raw[i]
|
||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if json[i] > ' ' {
|
if raw[i] > ' ' {
|
||||||
goto end
|
goto end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(raw); i++ {
|
||||||
if json[i] == vc {
|
if raw[i] == vc {
|
||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if json[i] > ' ' {
|
if raw[i] > ' ' {
|
||||||
goto end
|
goto end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,37 +332,37 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
|
||||||
r.a = make([]Result, 0)
|
r.a = make([]Result, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(raw); i++ {
|
||||||
if json[i] <= ' ' {
|
if raw[i] <= ' ' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// get next value
|
// get next value
|
||||||
if json[i] == ']' || json[i] == '}' {
|
if raw[i] == ']' || raw[i] == '}' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
switch json[i] {
|
switch raw[i] {
|
||||||
default:
|
default:
|
||||||
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
if (raw[i] >= '0' && raw[i] <= '9') || raw[i] == '-' {
|
||||||
value.Type = Number
|
value.Type = Number
|
||||||
value.Raw, value.Num = tonum(json[i:])
|
value.Raw, value.Num = toNum(raw[i:])
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case '{', '[':
|
case '{', '[':
|
||||||
value.Type = JSON
|
value.Type = JSON
|
||||||
value.Raw = squash(json[i:])
|
value.Raw = squash(raw[i:])
|
||||||
case 'n':
|
case 'n':
|
||||||
value.Type = Null
|
value.Type = Null
|
||||||
value.Raw = tolit(json[i:])
|
value.Raw = toLit(raw[i:])
|
||||||
case 't':
|
case 't':
|
||||||
value.Type = True
|
value.Type = True
|
||||||
value.Raw = tolit(json[i:])
|
value.Raw = toLit(raw[i:])
|
||||||
case 'f':
|
case 'f':
|
||||||
value.Type = False
|
value.Type = False
|
||||||
value.Raw = tolit(json[i:])
|
value.Raw = toLit(raw[i:])
|
||||||
case '"':
|
case '"':
|
||||||
value.Type = String
|
value.Type = String
|
||||||
value.Raw, value.Str = tostr(json[i:])
|
value.Raw, value.Str = toStr(raw[i:])
|
||||||
}
|
}
|
||||||
i += len(value.Raw) - 1
|
i += len(value.Raw) - 1
|
||||||
|
|
||||||
|
@ -405,22 +405,22 @@ func Parse(json string) Result {
|
||||||
default:
|
default:
|
||||||
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
||||||
value.Type = Number
|
value.Type = Number
|
||||||
value.Raw, value.Num = tonum(json[i:])
|
value.Raw, value.Num = toNum(json[i:])
|
||||||
} else {
|
} else {
|
||||||
return Result{}
|
return Result{}
|
||||||
}
|
}
|
||||||
case 'n':
|
case 'n':
|
||||||
value.Type = Null
|
value.Type = Null
|
||||||
value.Raw = tolit(json[i:])
|
value.Raw = toLit(json[i:])
|
||||||
case 't':
|
case 't':
|
||||||
value.Type = True
|
value.Type = True
|
||||||
value.Raw = tolit(json[i:])
|
value.Raw = toLit(json[i:])
|
||||||
case 'f':
|
case 'f':
|
||||||
value.Type = False
|
value.Type = False
|
||||||
value.Raw = tolit(json[i:])
|
value.Raw = toLit(json[i:])
|
||||||
case '"':
|
case '"':
|
||||||
value.Type = String
|
value.Type = String
|
||||||
value.Raw, value.Str = tostr(json[i:])
|
value.Raw, value.Str = toStr(json[i:])
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -433,27 +433,27 @@ func ParseBytes(json []byte) Result {
|
||||||
return Parse(string(json))
|
return Parse(string(json))
|
||||||
}
|
}
|
||||||
|
|
||||||
func squash(json string) string {
|
func squash(jsonString string) string {
|
||||||
// expects that the lead character is a '[' or '{'
|
// expects that the lead character is a '[' or '{'
|
||||||
// squash the value, ignoring all nested arrays and objects.
|
// squash the value, ignoring all nested arrays and objects.
|
||||||
// the first '[' or '{' has already been read
|
// the first '[' or '{' has already been read
|
||||||
depth := 1
|
depth := 1
|
||||||
for i := 1; i < len(json); i++ {
|
for i := 1; i < len(jsonString); i++ {
|
||||||
if json[i] >= '"' && json[i] <= '}' {
|
if jsonString[i] >= '"' && jsonString[i] <= '}' {
|
||||||
switch json[i] {
|
switch jsonString[i] {
|
||||||
case '"':
|
case '"':
|
||||||
i++
|
i++
|
||||||
s2 := i
|
s2 := i
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(jsonString); i++ {
|
||||||
if json[i] > '\\' {
|
if jsonString[i] > '\\' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if json[i] == '"' {
|
if jsonString[i] == '"' {
|
||||||
// look for an escaped slash
|
// look for an escaped slash
|
||||||
if json[i-1] == '\\' {
|
if jsonString[i-1] == '\\' {
|
||||||
n := 0
|
n := 0
|
||||||
for j := i - 2; j > s2-1; j-- {
|
for j := i - 2; j > s2-1; j-- {
|
||||||
if json[j] != '\\' {
|
if jsonString[j] != '\\' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n++
|
n++
|
||||||
|
@ -470,75 +470,75 @@ func squash(json string) string {
|
||||||
case '}', ']':
|
case '}', ']':
|
||||||
depth--
|
depth--
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
return json[:i+1]
|
return jsonString[:i+1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return json
|
return jsonString
|
||||||
}
|
}
|
||||||
|
|
||||||
func tonum(json string) (raw string, num float64) {
|
func toNum(jsonString string) (raw string, num float64) {
|
||||||
for i := 1; i < len(json); i++ {
|
for i := 1; i < len(jsonString); i++ {
|
||||||
// less than dash might have valid characters
|
// less than dash might have valid characters
|
||||||
if json[i] <= '-' {
|
if jsonString[i] <= '-' {
|
||||||
if json[i] <= ' ' || json[i] == ',' {
|
if jsonString[i] <= ' ' || jsonString[i] == ',' {
|
||||||
// break on whitespace and comma
|
// break on whitespace and comma
|
||||||
raw = json[:i]
|
raw = jsonString[:i]
|
||||||
num, _ = strconv.ParseFloat(raw, 64)
|
num, _ = strconv.ParseFloat(raw, 64)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// could be a '+' or '-'. let's assume so.
|
// could be a '+' or '-'. let's assume so.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if json[i] < ']' {
|
if jsonString[i] < ']' {
|
||||||
// probably a valid number
|
// probably a valid number
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if json[i] == 'e' || json[i] == 'E' {
|
if jsonString[i] == 'e' || jsonString[i] == 'E' {
|
||||||
// allow for exponential numbers
|
// allow for exponential numbers
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// likely a ']' or '}'
|
// likely a ']' or '}'
|
||||||
raw = json[:i]
|
raw = jsonString[:i]
|
||||||
num, _ = strconv.ParseFloat(raw, 64)
|
num, _ = strconv.ParseFloat(raw, 64)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
raw = json
|
raw = jsonString
|
||||||
num, _ = strconv.ParseFloat(raw, 64)
|
num, _ = strconv.ParseFloat(raw, 64)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func tolit(json string) (raw string) {
|
func toLit(jsonString string) (raw string) {
|
||||||
for i := 1; i < len(json); i++ {
|
for i := 1; i < len(jsonString); i++ {
|
||||||
if json[i] < 'a' || json[i] > 'z' {
|
if jsonString[i] < 'a' || jsonString[i] > 'z' {
|
||||||
return json[:i]
|
return jsonString[:i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return json
|
return jsonString
|
||||||
}
|
}
|
||||||
|
|
||||||
func tostr(json string) (raw string, str string) {
|
func toStr(jsonString string) (raw string, str string) {
|
||||||
// expects that the lead character is a '"'
|
// expects that the lead character is a '"'
|
||||||
for i := 1; i < len(json); i++ {
|
for i := 1; i < len(jsonString); i++ {
|
||||||
if json[i] > '\\' {
|
if jsonString[i] > '\\' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if json[i] == '"' {
|
if jsonString[i] == '"' {
|
||||||
return json[:i+1], json[1:i]
|
return jsonString[:i+1], jsonString[1:i]
|
||||||
}
|
}
|
||||||
if json[i] == '\\' {
|
if jsonString[i] == '\\' {
|
||||||
i++
|
i++
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(jsonString); i++ {
|
||||||
if json[i] > '\\' {
|
if jsonString[i] > '\\' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if json[i] == '"' {
|
if jsonString[i] == '"' {
|
||||||
// look for an escaped slash
|
// look for an escaped slash
|
||||||
if json[i-1] == '\\' {
|
if jsonString[i-1] == '\\' {
|
||||||
n := 0
|
n := 0
|
||||||
for j := i - 2; j > 0; j-- {
|
for j := i - 2; j > 0; j-- {
|
||||||
if json[j] != '\\' {
|
if jsonString[j] != '\\' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n++
|
n++
|
||||||
|
@ -551,15 +551,15 @@ func tostr(json string) (raw string, str string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var ret string
|
var ret string
|
||||||
if i+1 < len(json) {
|
if i+1 < len(jsonString) {
|
||||||
ret = json[:i+1]
|
ret = jsonString[:i+1]
|
||||||
} else {
|
} else {
|
||||||
ret = json[:i]
|
ret = jsonString[:i]
|
||||||
}
|
}
|
||||||
return ret, unescape(json[1:i])
|
return ret, unescape(jsonString[1:i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return json, json[1:]
|
return jsonString, jsonString[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists returns true if value exists.
|
// Exists returns true if value exists.
|
||||||
|
@ -919,7 +919,7 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
|
||||||
}
|
}
|
||||||
if c.json[i] == '"' {
|
if c.json[i] == '"' {
|
||||||
i, key, kesc, ok = i+1, c.json[s:i], false, true
|
i, key, kesc, ok = i+1, c.json[s:i], false, true
|
||||||
goto parse_key_string_done
|
goto parseKeyStringDone
|
||||||
}
|
}
|
||||||
if c.json[i] == '\\' {
|
if c.json[i] == '\\' {
|
||||||
i++
|
i++
|
||||||
|
@ -942,14 +942,14 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i, key, kesc, ok = i+1, c.json[s:i], true, true
|
i, key, kesc, ok = i+1, c.json[s:i], true, true
|
||||||
goto parse_key_string_done
|
goto parseKeyStringDone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
key, kesc, ok = c.json[s:], false, false
|
key, kesc, ok = c.json[s:], false, false
|
||||||
parse_key_string_done:
|
parseKeyStringDone:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if c.json[i] == '}' {
|
if c.json[i] == '}' {
|
||||||
|
@ -1426,37 +1426,37 @@ func fromBytesGet(result Result) Result {
|
||||||
|
|
||||||
// GetBytes searches json for the specified path.
|
// GetBytes searches json for the specified path.
|
||||||
// If working with bytes, this method preferred over Get(string(data), path)
|
// If working with bytes, this method preferred over Get(string(data), path)
|
||||||
func GetBytes(json []byte, path string) Result {
|
func GetBytes(raw []byte, path string) Result {
|
||||||
var result Result
|
var result Result
|
||||||
if json != nil {
|
if raw != nil {
|
||||||
// unsafe cast to string
|
// unsafe cast to string
|
||||||
result = Get(*(*string)(unsafe.Pointer(&json)), path)
|
result = Get(*(*string)(unsafe.Pointer(&raw)), path)
|
||||||
result = fromBytesGet(result)
|
result = fromBytesGet(result)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// runeit returns the rune from the the \uXXXX
|
// runeIt returns the rune from the the \uXXXX
|
||||||
func runeit(json string) rune {
|
func runeIt(jsonString string) rune {
|
||||||
n, _ := strconv.ParseUint(json[:4], 16, 64)
|
n, _ := strconv.ParseUint(jsonString[:4], 16, 64)
|
||||||
return rune(n)
|
return rune(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// unescape unescapes a string
|
// unescape unescapes a string
|
||||||
func unescape(json string) string { //, error) {
|
func unescape(jsonString string) string { //, error) {
|
||||||
var str = make([]byte, 0, len(json))
|
var str = make([]byte, 0, len(jsonString))
|
||||||
for i := 0; i < len(json); i++ {
|
for i := 0; i < len(jsonString); i++ {
|
||||||
switch {
|
switch {
|
||||||
default:
|
default:
|
||||||
str = append(str, json[i])
|
str = append(str, jsonString[i])
|
||||||
case json[i] < ' ':
|
case jsonString[i] < ' ':
|
||||||
return string(str)
|
return string(str)
|
||||||
case json[i] == '\\':
|
case jsonString[i] == '\\':
|
||||||
i++
|
i++
|
||||||
if i >= len(json) {
|
if i >= len(jsonString) {
|
||||||
return string(str)
|
return string(str)
|
||||||
}
|
}
|
||||||
switch json[i] {
|
switch jsonString[i] {
|
||||||
default:
|
default:
|
||||||
return string(str)
|
return string(str)
|
||||||
case '\\':
|
case '\\':
|
||||||
|
@ -1476,16 +1476,16 @@ func unescape(json string) string { //, error) {
|
||||||
case '"':
|
case '"':
|
||||||
str = append(str, '"')
|
str = append(str, '"')
|
||||||
case 'u':
|
case 'u':
|
||||||
if i+5 > len(json) {
|
if i+5 > len(jsonString) {
|
||||||
return string(str)
|
return string(str)
|
||||||
}
|
}
|
||||||
r := runeit(json[i+1:])
|
r := runeIt(jsonString[i+1:])
|
||||||
i += 5
|
i += 5
|
||||||
if utf16.IsSurrogate(r) {
|
if utf16.IsSurrogate(r) {
|
||||||
// need another code
|
// need another code
|
||||||
if len(json[i:]) >= 6 && json[i] == '\\' && json[i+1] == 'u' {
|
if len(jsonString[i:]) >= 6 && jsonString[i] == '\\' && jsonString[i+1] == 'u' {
|
||||||
// we expect it to be correct so just consume it
|
// we expect it to be correct so just consume it
|
||||||
r = utf16.DecodeRune(r, runeit(json[i+2:]))
|
r = utf16.DecodeRune(r, runeIt(jsonString[i+2:]))
|
||||||
i += 6
|
i += 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1565,27 +1565,27 @@ func stringLessInsensitive(a, b string) bool {
|
||||||
// parseAny parses the next value from a json string.
|
// parseAny parses the next value from a json string.
|
||||||
// A Result is returned when the hit param is set.
|
// A Result is returned when the hit param is set.
|
||||||
// The return values are (i int, res Result, ok bool)
|
// The return values are (i int, res Result, ok bool)
|
||||||
func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
func parseAny(jsonString string, i int, hit bool) (int, Result, bool) {
|
||||||
var res Result
|
var res Result
|
||||||
var val string
|
var val string
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(jsonString); i++ {
|
||||||
if json[i] == '{' || json[i] == '[' {
|
if jsonString[i] == '{' || jsonString[i] == '[' {
|
||||||
i, val = parseSquash(json, i)
|
i, val = parseSquash(jsonString, i)
|
||||||
if hit {
|
if hit {
|
||||||
res.Raw = val
|
res.Raw = val
|
||||||
res.Type = JSON
|
res.Type = JSON
|
||||||
}
|
}
|
||||||
return i, res, true
|
return i, res, true
|
||||||
}
|
}
|
||||||
if json[i] <= ' ' {
|
if jsonString[i] <= ' ' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch json[i] {
|
switch jsonString[i] {
|
||||||
case '"':
|
case '"':
|
||||||
i++
|
i++
|
||||||
var vesc bool
|
var vesc bool
|
||||||
var ok bool
|
var ok bool
|
||||||
i, val, vesc, ok = parseString(json, i)
|
i, val, vesc, ok = parseString(jsonString, i)
|
||||||
if !ok {
|
if !ok {
|
||||||
return i, res, false
|
return i, res, false
|
||||||
}
|
}
|
||||||
|
@ -1600,7 +1600,7 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
||||||
}
|
}
|
||||||
return i, res, true
|
return i, res, true
|
||||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
i, val = parseNumber(json, i)
|
i, val = parseNumber(jsonString, i)
|
||||||
if hit {
|
if hit {
|
||||||
res.Raw = val
|
res.Raw = val
|
||||||
res.Type = Number
|
res.Type = Number
|
||||||
|
@ -1608,8 +1608,8 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
||||||
}
|
}
|
||||||
return i, res, true
|
return i, res, true
|
||||||
case 't', 'f', 'n':
|
case 't', 'f', 'n':
|
||||||
vc := json[i]
|
vc := jsonString[i]
|
||||||
i, val = parseLiteral(json, i)
|
i, val = parseLiteral(jsonString, i)
|
||||||
if hit {
|
if hit {
|
||||||
res.Raw = val
|
res.Raw = val
|
||||||
switch vc {
|
switch vc {
|
||||||
|
@ -1633,10 +1633,10 @@ var ( // used for testing
|
||||||
// GetMany searches json for the multiple paths.
|
// GetMany searches json for the multiple paths.
|
||||||
// The return value is a Result array where the number of items
|
// The return value is a Result array where the number of items
|
||||||
// will be equal to the number of input paths.
|
// will be equal to the number of input paths.
|
||||||
func GetMany(json string, path ...string) []Result {
|
func GetMany(jsonString string, path ...string) []Result {
|
||||||
res := make([]Result, len(path))
|
res := make([]Result, len(path))
|
||||||
for i, path := range path {
|
for i, path := range path {
|
||||||
res[i] = Get(json, path)
|
res[i] = Get(jsonString, path)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -1651,31 +1651,31 @@ func GetManyBytes(json []byte, path ...string) []Result {
|
||||||
var fieldsmu sync.RWMutex
|
var fieldsmu sync.RWMutex
|
||||||
var fields = make(map[string]map[string]int)
|
var fields = make(map[string]map[string]int)
|
||||||
|
|
||||||
func assign(jsval Result, goval reflect.Value) {
|
func assign(jsVal Result, goVal reflect.Value) {
|
||||||
if jsval.Type == Null {
|
if jsVal.Type == Null {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch goval.Kind() {
|
switch goVal.Kind() {
|
||||||
default:
|
default:
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
if !goval.IsNil() {
|
if !goVal.IsNil() {
|
||||||
newval := reflect.New(goval.Elem().Type())
|
newval := reflect.New(goVal.Elem().Type())
|
||||||
assign(jsval, newval.Elem())
|
assign(jsVal, newval.Elem())
|
||||||
goval.Elem().Set(newval.Elem())
|
goVal.Elem().Set(newval.Elem())
|
||||||
} else {
|
} else {
|
||||||
newval := reflect.New(goval.Type().Elem())
|
newval := reflect.New(goVal.Type().Elem())
|
||||||
assign(jsval, newval.Elem())
|
assign(jsVal, newval.Elem())
|
||||||
goval.Set(newval)
|
goVal.Set(newval)
|
||||||
}
|
}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
fieldsmu.RLock()
|
fieldsmu.RLock()
|
||||||
sf := fields[goval.Type().String()]
|
sf := fields[goVal.Type().String()]
|
||||||
fieldsmu.RUnlock()
|
fieldsmu.RUnlock()
|
||||||
if sf == nil {
|
if sf == nil {
|
||||||
fieldsmu.Lock()
|
fieldsmu.Lock()
|
||||||
sf = make(map[string]int)
|
sf = make(map[string]int)
|
||||||
for i := 0; i < goval.Type().NumField(); i++ {
|
for i := 0; i < goVal.Type().NumField(); i++ {
|
||||||
f := goval.Type().Field(i)
|
f := goVal.Type().Field(i)
|
||||||
tag := strings.Split(f.Tag.Get("json"), ",")[0]
|
tag := strings.Split(f.Tag.Get("json"), ",")[0]
|
||||||
if tag != "-" {
|
if tag != "-" {
|
||||||
if tag != "" {
|
if tag != "" {
|
||||||
|
@ -1686,12 +1686,12 @@ func assign(jsval Result, goval reflect.Value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fields[goval.Type().String()] = sf
|
fields[goVal.Type().String()] = sf
|
||||||
fieldsmu.Unlock()
|
fieldsmu.Unlock()
|
||||||
}
|
}
|
||||||
jsval.ForEach(func(key, value Result) bool {
|
jsVal.ForEach(func(key, value Result) bool {
|
||||||
if idx, ok := sf[key.Str]; ok {
|
if idx, ok := sf[key.Str]; ok {
|
||||||
f := goval.Field(idx)
|
f := goVal.Field(idx)
|
||||||
if f.CanSet() {
|
if f.CanSet() {
|
||||||
assign(value, f)
|
assign(value, f)
|
||||||
}
|
}
|
||||||
|
@ -1699,49 +1699,49 @@ func assign(jsval Result, goval reflect.Value) {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if goval.Type().Elem().Kind() == reflect.Uint8 && jsval.Type == String {
|
if goVal.Type().Elem().Kind() == reflect.Uint8 && jsVal.Type == String {
|
||||||
data, _ := base64.StdEncoding.DecodeString(jsval.String())
|
data, _ := base64.StdEncoding.DecodeString(jsVal.String())
|
||||||
goval.Set(reflect.ValueOf(data))
|
goVal.Set(reflect.ValueOf(data))
|
||||||
} else {
|
} else {
|
||||||
jsvals := jsval.Array()
|
jsvals := jsVal.Array()
|
||||||
slice := reflect.MakeSlice(goval.Type(), len(jsvals), len(jsvals))
|
slice := reflect.MakeSlice(goVal.Type(), len(jsvals), len(jsvals))
|
||||||
for i := 0; i < len(jsvals); i++ {
|
for i := 0; i < len(jsvals); i++ {
|
||||||
assign(jsvals[i], slice.Index(i))
|
assign(jsvals[i], slice.Index(i))
|
||||||
}
|
}
|
||||||
goval.Set(slice)
|
goVal.Set(slice)
|
||||||
}
|
}
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
i, n := 0, goval.Len()
|
i, n := 0, goVal.Len()
|
||||||
jsval.ForEach(func(_, value Result) bool {
|
jsVal.ForEach(func(_, value Result) bool {
|
||||||
if i == n {
|
if i == n {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
assign(value, goval.Index(i))
|
assign(value, goVal.Index(i))
|
||||||
i++
|
i++
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
if goval.Type().Key().Kind() == reflect.String && goval.Type().Elem().Kind() == reflect.Interface {
|
if goVal.Type().Key().Kind() == reflect.String && goVal.Type().Elem().Kind() == reflect.Interface {
|
||||||
goval.Set(reflect.ValueOf(jsval.Value()))
|
goVal.Set(reflect.ValueOf(jsVal.Value()))
|
||||||
}
|
}
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
goval.Set(reflect.ValueOf(jsval.Value()))
|
goVal.Set(reflect.ValueOf(jsVal.Value()))
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
goval.SetBool(jsval.Bool())
|
goVal.SetBool(jsVal.Bool())
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
goval.SetFloat(jsval.Float())
|
goVal.SetFloat(jsVal.Float())
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
goval.SetInt(jsval.Int())
|
goVal.SetInt(jsVal.Int())
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
goval.SetUint(jsval.Uint())
|
goVal.SetUint(jsVal.Uint())
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
goval.SetString(jsval.String())
|
goVal.SetString(jsVal.String())
|
||||||
}
|
}
|
||||||
if len(goval.Type().PkgPath()) > 0 {
|
if len(goVal.Type().PkgPath()) > 0 {
|
||||||
v := goval.Addr()
|
v := goVal.Addr()
|
||||||
if v.Type().NumMethod() > 0 {
|
if v.Type().NumMethod() > 0 {
|
||||||
if u, ok := v.Interface().(json.Unmarshaler); ok {
|
if u, ok := v.Interface().(json.Unmarshaler); ok {
|
||||||
u.UnmarshalJSON([]byte(jsval.Raw))
|
u.UnmarshalJSON([]byte(jsVal.Raw))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1771,7 +1771,7 @@ func UnmarshalValidationEnabled(enabled bool) {
|
||||||
// Deprecated: Use encoder/json.Unmarshal instead
|
// Deprecated: Use encoder/json.Unmarshal instead
|
||||||
func Unmarshal(data []byte, v interface{}) error {
|
func Unmarshal(data []byte, v interface{}) error {
|
||||||
if atomic.LoadUintptr(&validate) == 1 {
|
if atomic.LoadUintptr(&validate) == 1 {
|
||||||
_, ok := validpayload(data, 0)
|
_, ok := validPayload(data, 0)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("invalid json")
|
return errors.New("invalid json")
|
||||||
}
|
}
|
||||||
|
@ -1782,11 +1782,11 @@ func Unmarshal(data []byte, v interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validpayload(data []byte, i int) (outi int, ok bool) {
|
func validPayload(data []byte, i int) (outi int, ok bool) {
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
switch data[i] {
|
switch data[i] {
|
||||||
default:
|
default:
|
||||||
i, ok = validany(data, i)
|
i, ok = validAny(data, i)
|
||||||
if !ok {
|
if !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
|
@ -1805,7 +1805,7 @@ func validpayload(data []byte, i int) (outi int, ok bool) {
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validany(data []byte, i int) (outi int, ok bool) {
|
func validAny(data []byte, i int) (outi int, ok bool) {
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
switch data[i] {
|
switch data[i] {
|
||||||
default:
|
default:
|
||||||
|
@ -1813,24 +1813,24 @@ func validany(data []byte, i int) (outi int, ok bool) {
|
||||||
case ' ', '\t', '\n', '\r':
|
case ' ', '\t', '\n', '\r':
|
||||||
continue
|
continue
|
||||||
case '{':
|
case '{':
|
||||||
return validobject(data, i+1)
|
return validObject(data, i+1)
|
||||||
case '[':
|
case '[':
|
||||||
return validarray(data, i+1)
|
return validArray(data, i+1)
|
||||||
case '"':
|
case '"':
|
||||||
return validstring(data, i+1)
|
return validString(data, i+1)
|
||||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
return validnumber(data, i+1)
|
return validNumber(data, i+1)
|
||||||
case 't':
|
case 't':
|
||||||
return validtrue(data, i+1)
|
return validTrue(data, i+1)
|
||||||
case 'f':
|
case 'f':
|
||||||
return validfalse(data, i+1)
|
return validFalse(data, i+1)
|
||||||
case 'n':
|
case 'n':
|
||||||
return validnull(data, i+1)
|
return validNull(data, i+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validobject(data []byte, i int) (outi int, ok bool) {
|
func validObject(data []byte, i int) (outi int, ok bool) {
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
switch data[i] {
|
switch data[i] {
|
||||||
default:
|
default:
|
||||||
|
@ -1841,16 +1841,16 @@ func validobject(data []byte, i int) (outi int, ok bool) {
|
||||||
return i + 1, true
|
return i + 1, true
|
||||||
case '"':
|
case '"':
|
||||||
key:
|
key:
|
||||||
if i, ok = validstring(data, i+1); !ok {
|
if i, ok = validString(data, i+1); !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
if i, ok = validcolon(data, i); !ok {
|
if i, ok = validColon(data, i); !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
if i, ok = validany(data, i); !ok {
|
if i, ok = validAny(data, i); !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
if i, ok = validcomma(data, i, '}'); !ok {
|
if i, ok = validComma(data, i, '}'); !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
if data[i] == '}' {
|
if data[i] == '}' {
|
||||||
|
@ -1866,7 +1866,7 @@ func validobject(data []byte, i int) (outi int, ok bool) {
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validcolon(data []byte, i int) (outi int, ok bool) {
|
func validColon(data []byte, i int) (outi int, ok bool) {
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
switch data[i] {
|
switch data[i] {
|
||||||
default:
|
default:
|
||||||
|
@ -1879,7 +1879,7 @@ func validcolon(data []byte, i int) (outi int, ok bool) {
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validcomma(data []byte, i int, end byte) (outi int, ok bool) {
|
func validComma(data []byte, i int, end byte) (outi int, ok bool) {
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
switch data[i] {
|
switch data[i] {
|
||||||
default:
|
default:
|
||||||
|
@ -1894,15 +1894,15 @@ func validcomma(data []byte, i int, end byte) (outi int, ok bool) {
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validarray(data []byte, i int) (outi int, ok bool) {
|
func validArray(data []byte, i int) (outi int, ok bool) {
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
switch data[i] {
|
switch data[i] {
|
||||||
default:
|
default:
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
if i, ok = validany(data, i); !ok {
|
if i, ok = validAny(data, i); !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
if i, ok = validcomma(data, i, ']'); !ok {
|
if i, ok = validComma(data, i, ']'); !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
if data[i] == ']' {
|
if data[i] == ']' {
|
||||||
|
@ -1917,7 +1917,7 @@ func validarray(data []byte, i int) (outi int, ok bool) {
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validstring(data []byte, i int) (outi int, ok bool) {
|
func validString(data []byte, i int) (outi int, ok bool) {
|
||||||
for ; i < len(data); i++ {
|
for ; i < len(data); i++ {
|
||||||
if data[i] < ' ' {
|
if data[i] < ' ' {
|
||||||
return i, false
|
return i, false
|
||||||
|
@ -1949,7 +1949,7 @@ func validstring(data []byte, i int) (outi int, ok bool) {
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validnumber(data []byte, i int) (outi int, ok bool) {
|
func validNumber(data []byte, i int) (outi int, ok bool) {
|
||||||
i--
|
i--
|
||||||
// sign
|
// sign
|
||||||
if data[i] == '-' {
|
if data[i] == '-' {
|
||||||
|
@ -2018,19 +2018,19 @@ func validnumber(data []byte, i int) (outi int, ok bool) {
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func validtrue(data []byte, i int) (outi int, ok bool) {
|
func validTrue(data []byte, i int) (outi int, ok bool) {
|
||||||
if i+3 <= len(data) && data[i] == 'r' && data[i+1] == 'u' && data[i+2] == 'e' {
|
if i+3 <= len(data) && data[i] == 'r' && data[i+1] == 'u' && data[i+2] == 'e' {
|
||||||
return i + 3, true
|
return i + 3, true
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validfalse(data []byte, i int) (outi int, ok bool) {
|
func validFalse(data []byte, i int) (outi int, ok bool) {
|
||||||
if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' && data[i+2] == 's' && data[i+3] == 'e' {
|
if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' && data[i+2] == 's' && data[i+3] == 'e' {
|
||||||
return i + 4, true
|
return i + 4, true
|
||||||
}
|
}
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
func validnull(data []byte, i int) (outi int, ok bool) {
|
func validNull(data []byte, i int) (outi int, ok bool) {
|
||||||
if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' && data[i+2] == 'l' {
|
if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' && data[i+2] == 'l' {
|
||||||
return i + 3, true
|
return i + 3, true
|
||||||
}
|
}
|
||||||
|
@ -2039,7 +2039,7 @@ func validnull(data []byte, i int) (outi int, ok bool) {
|
||||||
|
|
||||||
// Valid returns true if the input is valid json.
|
// Valid returns true if the input is valid json.
|
||||||
func Valid(json string) bool {
|
func Valid(json string) bool {
|
||||||
_, ok := validpayload([]byte(json), 0)
|
_, ok := validPayload([]byte(json), 0)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -971,7 +971,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testvalid(json string, expect bool) {
|
func testvalid(json string, expect bool) {
|
||||||
_, ok := validpayload([]byte(json), 0)
|
_, ok := validPayload([]byte(json), 0)
|
||||||
if ok != expect {
|
if ok != expect {
|
||||||
panic("mismatch")
|
panic("mismatch")
|
||||||
}
|
}
|
||||||
|
@ -1062,14 +1062,14 @@ func TestValidRandom(t *testing.T) {
|
||||||
for time.Since(start) < time.Second*3 {
|
for time.Since(start) < time.Second*3 {
|
||||||
n := rand.Int() % len(b)
|
n := rand.Int() % len(b)
|
||||||
rand.Read(b[:n])
|
rand.Read(b[:n])
|
||||||
validpayload(b[:n], 0)
|
validPayload(b[:n], 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
for time.Since(start) < time.Second*3 {
|
for time.Since(start) < time.Second*3 {
|
||||||
n := rand.Int() % len(b)
|
n := rand.Int() % len(b)
|
||||||
makeRandomJSONChars(b[:n])
|
makeRandomJSONChars(b[:n])
|
||||||
validpayload(b[:n], 0)
|
validPayload(b[:n], 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue