mirror of https://github.com/tidwall/gjson.git
minor optz
This commit is contained in:
parent
19f9404e51
commit
81391efb66
207
gjson.go
207
gjson.go
|
@ -430,18 +430,14 @@ func (t Result) Value() interface{} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseString(json string, i int, raw bool) (int, string, bool, bool) {
|
func parseString(json string, i int) (int, string, bool, bool) {
|
||||||
var s = i
|
var s = i
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(json); i++ {
|
||||||
if json[i] > '\\' {
|
if json[i] > '\\' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if json[i] == '"' {
|
if json[i] == '"' {
|
||||||
if raw {
|
return i + 1, json[s-1 : i+1], false, true
|
||||||
return i + 1, json[s-1 : i+1], false, true
|
|
||||||
} else {
|
|
||||||
return i + 1, json[s:i], false, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if json[i] == '\\' {
|
if json[i] == '\\' {
|
||||||
i++
|
i++
|
||||||
|
@ -463,21 +459,13 @@ func parseString(json string, i int, raw bool) (int, string, bool, bool) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if raw {
|
return i + 1, json[s-1 : i+1], true, true
|
||||||
return i + 1, json[s-1 : i+1], true, true
|
|
||||||
} else {
|
|
||||||
return i + 1, json[s:i], true, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if raw {
|
return i, json[s-1:], false, false
|
||||||
return i, json[s-1:], false, false
|
|
||||||
} else {
|
|
||||||
return i, json[s:], false, false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseNumber(json string, i int) (int, string) {
|
func parseNumber(json string, i int) (int, string) {
|
||||||
|
@ -575,7 +563,7 @@ func parseObjectPath(path string) (
|
||||||
return path, "", wild, uc, false
|
return path, "", wild, uc, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func squashObjectOrArray(json string, i int) (int, string) {
|
func parseSquash(json string, i int) (int, 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
|
||||||
|
@ -623,17 +611,58 @@ func squashObjectOrArray(json string, i int) (int, string) {
|
||||||
return i, json[s:]
|
return i, json[s:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseObject(json string, i int, path string, value *Result) (int, bool) {
|
func parseObject(c *parseContext, i int, path string) (int, bool) {
|
||||||
var match, kesc, vesc, ok, hit bool
|
var match, kesc, vesc, ok, hit bool
|
||||||
var key, val string
|
var key, val string
|
||||||
part, npath, wild, uc, more := parseObjectPath(path)
|
part, npath, wild, uc, more := parseObjectPath(path)
|
||||||
for i < len(json) {
|
for i < len(c.json) {
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(c.json); i++ {
|
||||||
if json[i] == '"' {
|
if c.json[i] == '"' {
|
||||||
i, key, kesc, ok = parseString(json, i+1, false)
|
// parse_key_string
|
||||||
|
// this is slightly different from getting s string value
|
||||||
|
// because we don't need the outer quotes.
|
||||||
|
i++
|
||||||
|
var s = i
|
||||||
|
for ; i < len(c.json); i++ {
|
||||||
|
if c.json[i] > '\\' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.json[i] == '"' {
|
||||||
|
i, key, kesc, ok = i+1, c.json[s:i], false, true
|
||||||
|
goto parse_key_string_done
|
||||||
|
}
|
||||||
|
if c.json[i] == '\\' {
|
||||||
|
i++
|
||||||
|
for ; i < len(c.json); i++ {
|
||||||
|
if c.json[i] > '\\' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.json[i] == '"' {
|
||||||
|
// look for an escaped slash
|
||||||
|
if c.json[i-1] == '\\' {
|
||||||
|
n := 0
|
||||||
|
for j := i - 2; j > 0; j-- {
|
||||||
|
if c.json[j] != '\\' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if n%2 == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i, key, kesc, ok = i+1, c.json[s:i], true, true
|
||||||
|
goto parse_key_string_done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i, key, kesc, ok = i, c.json[s:], false, false
|
||||||
|
parse_key_string_done:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if json[i] == '}' {
|
if c.json[i] == '}' {
|
||||||
return i + 1, false
|
return i + 1, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,72 +683,72 @@ func parseObject(json string, i int, path string, value *Result) (int, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hit = match && !more
|
hit = match && !more
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(c.json); i++ {
|
||||||
switch json[i] {
|
switch c.json[i] {
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
case '"':
|
case '"':
|
||||||
i++
|
i++
|
||||||
i, val, vesc, ok = parseString(json, i, true)
|
i, val, vesc, ok = parseString(c.json, i)
|
||||||
if !ok {
|
if !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
if hit {
|
if hit {
|
||||||
if vesc {
|
if vesc {
|
||||||
value.Str = unescape(val[1 : len(val)-1])
|
c.value.Str = unescape(val[1 : len(val)-1])
|
||||||
} else {
|
} else {
|
||||||
value.Str = val[1 : len(val)-1]
|
c.value.Str = val[1 : len(val)-1]
|
||||||
}
|
}
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = String
|
c.value.Type = String
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
case '{':
|
case '{':
|
||||||
if match && !hit {
|
if match && !hit {
|
||||||
i, hit = parseObject(json, i+1, npath, value)
|
i, hit = parseObject(c, i+1, npath)
|
||||||
if hit {
|
if hit {
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i, val = squashObjectOrArray(json, i)
|
i, val = parseSquash(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = JSON
|
c.value.Type = JSON
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case '[':
|
case '[':
|
||||||
if match && !hit {
|
if match && !hit {
|
||||||
i, hit = parseArray(json, i+1, npath, value)
|
i, hit = parseArray(c, i+1, npath)
|
||||||
if hit {
|
if hit {
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i, val = squashObjectOrArray(json, i)
|
i, val = parseSquash(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = JSON
|
c.value.Type = JSON
|
||||||
return i, true
|
return i, 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(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = Number
|
c.value.Type = Number
|
||||||
value.Num, _ = strconv.ParseFloat(val, 64)
|
c.value.Num, _ = strconv.ParseFloat(val, 64)
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
case 't', 'f', 'n':
|
case 't', 'f', 'n':
|
||||||
vc := json[i]
|
vc := c.json[i]
|
||||||
i, val = parseLiteral(json, i)
|
i, val = parseLiteral(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
switch vc {
|
switch vc {
|
||||||
case 't':
|
case 't':
|
||||||
value.Type = True
|
c.value.Type = True
|
||||||
case 'f':
|
case 'f':
|
||||||
value.Type = False
|
c.value.Type = False
|
||||||
}
|
}
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
|
@ -730,7 +759,7 @@ func parseObject(json string, i int, path string, value *Result) (int, bool) {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
var match, vesc, ok, hit bool
|
var match, vesc, ok, hit bool
|
||||||
var val string
|
var val string
|
||||||
var h int
|
var h int
|
||||||
|
@ -745,7 +774,7 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
||||||
partidx = int(n)
|
partidx = int(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i < len(json) {
|
for i < len(c.json) {
|
||||||
if !arrch {
|
if !arrch {
|
||||||
match = partidx == h
|
match = partidx == h
|
||||||
hit = match && !more
|
hit = match && !more
|
||||||
|
@ -754,13 +783,13 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
||||||
if alogok {
|
if alogok {
|
||||||
alog = append(alog, i)
|
alog = append(alog, i)
|
||||||
}
|
}
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(c.json); i++ {
|
||||||
switch json[i] {
|
switch c.json[i] {
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
case '"':
|
case '"':
|
||||||
i++
|
i++
|
||||||
i, val, vesc, ok = parseString(json, i, true)
|
i, val, vesc, ok = parseString(c.json, i)
|
||||||
if !ok {
|
if !ok {
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
|
@ -769,17 +798,17 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if vesc {
|
if vesc {
|
||||||
value.Str = unescape(val[1 : len(val)-1])
|
c.value.Str = unescape(val[1 : len(val)-1])
|
||||||
} else {
|
} else {
|
||||||
value.Str = val[1 : len(val)-1]
|
c.value.Str = val[1 : len(val)-1]
|
||||||
}
|
}
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = String
|
c.value.Type = String
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
case '{':
|
case '{':
|
||||||
if match && !hit {
|
if match && !hit {
|
||||||
i, hit = parseObject(json, i+1, npath, value)
|
i, hit = parseObject(c, i+1, npath)
|
||||||
if hit {
|
if hit {
|
||||||
if alogok {
|
if alogok {
|
||||||
break
|
break
|
||||||
|
@ -787,19 +816,19 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i, val = squashObjectOrArray(json, i)
|
i, val = parseSquash(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
if alogok {
|
if alogok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = JSON
|
c.value.Type = JSON
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case '[':
|
case '[':
|
||||||
if match && !hit {
|
if match && !hit {
|
||||||
i, hit = parseArray(json, i+1, npath, value)
|
i, hit = parseArray(c, i+1, npath)
|
||||||
if hit {
|
if hit {
|
||||||
if alogok {
|
if alogok {
|
||||||
break
|
break
|
||||||
|
@ -807,51 +836,50 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i, val = squashObjectOrArray(json, i)
|
i, val = parseSquash(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
if alogok {
|
if alogok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = JSON
|
c.value.Type = JSON
|
||||||
return i, true
|
return i, 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(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
if alogok {
|
if alogok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = Number
|
c.value.Type = Number
|
||||||
value.Num, _ = strconv.ParseFloat(val, 64)
|
c.value.Num, _ = strconv.ParseFloat(val, 64)
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
case 't', 'f', 'n':
|
case 't', 'f', 'n':
|
||||||
vc := json[i]
|
vc := c.json[i]
|
||||||
i, val = parseLiteral(json, i)
|
i, val = parseLiteral(c.json, i)
|
||||||
if hit {
|
if hit {
|
||||||
if alogok {
|
if alogok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
switch vc {
|
switch vc {
|
||||||
case 't':
|
case 't':
|
||||||
value.Type = True
|
c.value.Type = True
|
||||||
case 'f':
|
case 'f':
|
||||||
value.Type = False
|
c.value.Type = False
|
||||||
}
|
}
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
case ']':
|
case ']':
|
||||||
// TODO... '#' counter?
|
|
||||||
if arrch && part == "#" {
|
if arrch && part == "#" {
|
||||||
if alogok {
|
if alogok {
|
||||||
var jsons = make([]byte, 0, 64)
|
var jsons = make([]byte, 0, 64)
|
||||||
jsons = append(jsons, '[')
|
jsons = append(jsons, '[')
|
||||||
for j := 0; j < len(alog); j++ {
|
for j := 0; j < len(alog); j++ {
|
||||||
res := Get(json[alog[j]:], alogkey)
|
res := Get(c.json[alog[j]:], alogkey)
|
||||||
if res.Exists() {
|
if res.Exists() {
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
jsons = append(jsons, ',')
|
jsons = append(jsons, ',')
|
||||||
|
@ -860,16 +888,16 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsons = append(jsons, ']')
|
jsons = append(jsons, ']')
|
||||||
value.Type = JSON
|
c.value.Type = JSON
|
||||||
value.Raw = string(jsons)
|
c.value.Raw = string(jsons)
|
||||||
return i + 1, true
|
return i + 1, true
|
||||||
} else {
|
} else {
|
||||||
if alogok {
|
if alogok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
value.Raw = val
|
c.value.Raw = val
|
||||||
value.Type = Number
|
c.value.Type = Number
|
||||||
value.Num = float64(h - 1)
|
c.value.Num = float64(h - 1)
|
||||||
return i + 1, true
|
return i + 1, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -912,20 +940,25 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
|
||||||
//
|
//
|
||||||
func Get(json, path string) Result {
|
func Get(json, path string) Result {
|
||||||
var i int
|
var i int
|
||||||
var value Result
|
var c = &parseContext{json: json}
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(c.json); i++ {
|
||||||
if json[i] == '{' {
|
if c.json[i] == '{' {
|
||||||
i++
|
i++
|
||||||
parseObject(json, i, path, &value)
|
parseObject(c, i, path)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if json[i] == '[' {
|
if c.json[i] == '[' {
|
||||||
i++
|
i++
|
||||||
parseArray(json, i, path, &value)
|
parseArray(c, i, path)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value
|
return c.value
|
||||||
|
}
|
||||||
|
|
||||||
|
type parseContext struct {
|
||||||
|
json string
|
||||||
|
value Result
|
||||||
}
|
}
|
||||||
|
|
||||||
// unescape unescapes a string
|
// unescape unescapes a string
|
||||||
|
|
Loading…
Reference in New Issue