mirror of https://github.com/tidwall/gjson.git
Removed Multi. Added Parse and result.Get funcs
The Multi field was too bulky. fixes #4 Added a Parse(json) function that will do a simple parse of json. Added a result.Get(path) function that returns a child result. Added Bool(), Int(), and Float() to result type. fixes #5
This commit is contained in:
parent
44a8706c89
commit
cd422a3e10
50
README.md
50
README.md
|
@ -56,7 +56,7 @@ To access an array value use the index as the key.
|
||||||
To get the number of elements in an array or to access a child path, use the '#' character.
|
To get the number of elements in an array or to access a child path, use the '#' character.
|
||||||
The dot and wildcard characters can be escaped with '\'.
|
The dot and wildcard characters can be escaped with '\'.
|
||||||
|
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"name": {"first": "Tom", "last": "Anderson"},
|
"name": {"first": "Tom", "last": "Anderson"},
|
||||||
"age":37,
|
"age":37,
|
||||||
|
@ -93,16 +93,6 @@ string, for JSON string literals
|
||||||
nil, for JSON null
|
nil, for JSON null
|
||||||
```
|
```
|
||||||
|
|
||||||
To get the Go value call the `Value()` method:
|
|
||||||
|
|
||||||
|
|
||||||
```go
|
|
||||||
result.Value() // interface{} which may be nil, string, float64, or bool
|
|
||||||
|
|
||||||
// Or just get the value in one step.
|
|
||||||
gjson.Get(json, "name.last").Value()
|
|
||||||
```
|
|
||||||
|
|
||||||
To directly access the value:
|
To directly access the value:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -113,6 +103,30 @@ result.Raw // holds the raw json
|
||||||
result.Multi // holds nested array values
|
result.Multi // holds nested array values
|
||||||
```
|
```
|
||||||
|
|
||||||
|
There are a variety of handy functions that work on a result:
|
||||||
|
|
||||||
|
```go
|
||||||
|
result.Value() interface{}
|
||||||
|
result.Int() int64
|
||||||
|
result.Float() float64
|
||||||
|
result.String() string
|
||||||
|
result.Bool() bool
|
||||||
|
result.Array() []gjson.Result
|
||||||
|
result.Map() map[string]gjson.Result
|
||||||
|
result.Get(path string) Result
|
||||||
|
```
|
||||||
|
|
||||||
|
The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types:
|
||||||
|
|
||||||
|
```go
|
||||||
|
boolean >> bool
|
||||||
|
number >> float64
|
||||||
|
string >> string
|
||||||
|
null >> nil
|
||||||
|
array >> []interface{}
|
||||||
|
object >> map[string]interface{}
|
||||||
|
```
|
||||||
|
|
||||||
## Get nested array values
|
## Get nested array values
|
||||||
|
|
||||||
Suppose you want all the last names from the following json:
|
Suppose you want all the last names from the following json:
|
||||||
|
@ -138,11 +152,23 @@ You would use the path "programmers.#.lastName" like such:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
result := gjson.Get(json, "programmers.#.lastName")
|
result := gjson.Get(json, "programmers.#.lastName")
|
||||||
for _,name := range result.Multi {
|
for _,name := range result.Array() {
|
||||||
println(name.String())
|
println(name.String())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Simple Parse and Get
|
||||||
|
|
||||||
|
There's a `Parse(json)` function that will do a simple parse, and `result.Get(path)` that will search a result.
|
||||||
|
|
||||||
|
For example, all of these will return the same result:
|
||||||
|
|
||||||
|
```go
|
||||||
|
Parse(json).Get("name").Get("last")
|
||||||
|
Get("name").Get("last")
|
||||||
|
Get("name.last")
|
||||||
|
```
|
||||||
|
|
||||||
## Check for the existence of a value
|
## Check for the existence of a value
|
||||||
|
|
||||||
Sometimes you may want to see if the value actually existed in the json document.
|
Sometimes you may want to see if the value actually existed in the json document.
|
||||||
|
|
373
gjson.go
373
gjson.go
|
@ -19,8 +19,6 @@ const (
|
||||||
True
|
True
|
||||||
// JSON is a raw block of JSON
|
// JSON is a raw block of JSON
|
||||||
JSON
|
JSON
|
||||||
// Multi is a subset of results
|
|
||||||
Multi
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Result represents a json value that is returned from Get().
|
// Result represents a json value that is returned from Get().
|
||||||
|
@ -33,8 +31,6 @@ type Result struct {
|
||||||
Str string
|
Str string
|
||||||
// Num is the json number
|
// Num is the json number
|
||||||
Num float64
|
Num float64
|
||||||
// Multi is the subset of results
|
|
||||||
Multi []Result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of the value.
|
// String returns a string representation of the value.
|
||||||
|
@ -48,15 +44,6 @@ func (t Result) String() string {
|
||||||
return strconv.FormatFloat(t.Num, 'f', -1, 64)
|
return strconv.FormatFloat(t.Num, 'f', -1, 64)
|
||||||
case String:
|
case String:
|
||||||
return t.Str
|
return t.Str
|
||||||
case Multi:
|
|
||||||
var str string
|
|
||||||
for i, res := range t.Multi {
|
|
||||||
if i > 0 {
|
|
||||||
str += ","
|
|
||||||
}
|
|
||||||
str += res.String()
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
case JSON:
|
case JSON:
|
||||||
return t.Raw
|
return t.Raw
|
||||||
case True:
|
case True:
|
||||||
|
@ -64,6 +51,316 @@ func (t Result) String() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool returns an boolean representation.
|
||||||
|
func (t Result) Bool() bool {
|
||||||
|
switch t.Type {
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
case True:
|
||||||
|
return true
|
||||||
|
case String:
|
||||||
|
return t.Str != "" && t.Str != "0"
|
||||||
|
case Number:
|
||||||
|
return t.Num != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns an integer representation.
|
||||||
|
func (t Result) Int() int64 {
|
||||||
|
switch t.Type {
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
case True:
|
||||||
|
return 1
|
||||||
|
case String:
|
||||||
|
n, _ := strconv.ParseInt(t.Str, 10, 64)
|
||||||
|
return n
|
||||||
|
case Number:
|
||||||
|
return int64(t.Num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float returns an float64 representation.
|
||||||
|
func (t Result) Float() float64 {
|
||||||
|
switch t.Type {
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
case True:
|
||||||
|
return 1
|
||||||
|
case String:
|
||||||
|
n, _ := strconv.ParseFloat(t.Str, 64)
|
||||||
|
return n
|
||||||
|
case Number:
|
||||||
|
return t.Num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array returns back an array of children. The result must be a JSON array.
|
||||||
|
func (t Result) Array() []Result {
|
||||||
|
if t.Type != JSON {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
a, _, _ := t.arrayOrMap('[')
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map returns back an map of children. The result should be a JSON array.
|
||||||
|
func (t Result) Map() map[string]Result {
|
||||||
|
if t.Type != JSON {
|
||||||
|
return map[string]Result{}
|
||||||
|
}
|
||||||
|
_, o, _ := t.arrayOrMap('{')
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get searches result for the specified path.
|
||||||
|
// The result should be a JSON array or object.
|
||||||
|
func (t Result) Get(path string) Result {
|
||||||
|
return Get(t.Raw, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Result) arrayOrMap(vc byte) ([]Result, map[string]Result, byte) {
|
||||||
|
var a = []Result{}
|
||||||
|
var o = map[string]Result{}
|
||||||
|
var json = t.Raw
|
||||||
|
var i int
|
||||||
|
var value Result
|
||||||
|
var count int
|
||||||
|
var key Result
|
||||||
|
if vc == 0 {
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] == '{' || json[i] == '[' {
|
||||||
|
vc = json[i]
|
||||||
|
i++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if json[i] > ' ' {
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] == vc {
|
||||||
|
i++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if json[i] > ' ' {
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] <= ' ' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// get next value
|
||||||
|
if json[i] == ']' || json[i] == '}' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch json[i] {
|
||||||
|
default:
|
||||||
|
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
||||||
|
value.Type = Number
|
||||||
|
value.Raw, value.Num = tonum(json[i:])
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case '{', '[':
|
||||||
|
value.Type = JSON
|
||||||
|
value.Raw = squash(json[i:])
|
||||||
|
case 'n':
|
||||||
|
value.Type = Null
|
||||||
|
value.Raw = tolit(json[i:])
|
||||||
|
case 't':
|
||||||
|
value.Type = True
|
||||||
|
value.Raw = tolit(json[i:])
|
||||||
|
case 'f':
|
||||||
|
value.Type = False
|
||||||
|
value.Raw = tolit(json[i:])
|
||||||
|
case '"':
|
||||||
|
value.Type = String
|
||||||
|
value.Raw, value.Str = tostr(json[i:])
|
||||||
|
}
|
||||||
|
i += len(value.Raw) - 1
|
||||||
|
|
||||||
|
if vc == '{' {
|
||||||
|
if count%2 == 0 {
|
||||||
|
key = value
|
||||||
|
} else {
|
||||||
|
o[key.Str] = value
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
} else {
|
||||||
|
a = append(a, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
return a, o, vc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the json and returns a result
|
||||||
|
func Parse(json string) Result {
|
||||||
|
var value Result
|
||||||
|
for i := 0; i < len(json); i++ {
|
||||||
|
if json[i] <= ' ' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch json[i] {
|
||||||
|
default:
|
||||||
|
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
||||||
|
value.Type = Number
|
||||||
|
value.Raw, value.Num = tonum(json[i:])
|
||||||
|
} else {
|
||||||
|
return Result{}
|
||||||
|
}
|
||||||
|
case '{', '[':
|
||||||
|
value.Type = JSON
|
||||||
|
value.Raw = json[i:]
|
||||||
|
// we just trim the tail end
|
||||||
|
for value.Raw[len(value.Raw)-1] <= ' ' {
|
||||||
|
value.Raw = value.Raw[:len(value.Raw)-1]
|
||||||
|
}
|
||||||
|
case 'n':
|
||||||
|
value.Type = Null
|
||||||
|
value.Raw = tolit(json[i:])
|
||||||
|
case 't':
|
||||||
|
value.Type = True
|
||||||
|
value.Raw = tolit(json[i:])
|
||||||
|
case 'f':
|
||||||
|
value.Type = False
|
||||||
|
value.Raw = tolit(json[i:])
|
||||||
|
case '"':
|
||||||
|
value.Type = String
|
||||||
|
value.Raw, value.Str = tostr(json[i:])
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func squash(json string) string {
|
||||||
|
// expects that the lead character is a '[' or '{'
|
||||||
|
// squash the value, ignoring all nested arrays and objects.
|
||||||
|
// the first '[' or '{' has already been read
|
||||||
|
depth := 1
|
||||||
|
for i := 1; i < len(json); i++ {
|
||||||
|
if json[i] >= '"' && json[i] <= '}' {
|
||||||
|
switch json[i] {
|
||||||
|
case '"':
|
||||||
|
i++
|
||||||
|
s2 := i
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] > '\\' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if json[i] == '"' {
|
||||||
|
// look for an escaped slash
|
||||||
|
if json[i-1] == '\\' {
|
||||||
|
n := 0
|
||||||
|
for j := i - 2; j > s2-1; j-- {
|
||||||
|
if json[j] != '\\' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if n%2 == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '{', '[':
|
||||||
|
depth++
|
||||||
|
case '}', ']':
|
||||||
|
depth--
|
||||||
|
if depth == 0 {
|
||||||
|
return json[:i+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
func tonum(json string) (raw string, num float64) {
|
||||||
|
for i := 1; i < len(json); i++ {
|
||||||
|
// less than dash might have valid characters
|
||||||
|
if json[i] <= '-' {
|
||||||
|
if json[i] <= ' ' || json[i] == ',' {
|
||||||
|
// break on whitespace and comma
|
||||||
|
raw = json[:i]
|
||||||
|
num, _ = strconv.ParseFloat(raw, 64)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// could be a '+' or '-'. let's assume so.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if json[i] < ']' {
|
||||||
|
// probably a valid number
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if json[i] == 'e' || json[i] == 'E' {
|
||||||
|
// allow for exponential numbers
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// likely a ']' or '}'
|
||||||
|
raw = json[:i]
|
||||||
|
num, _ = strconv.ParseFloat(raw, 64)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
raw = json
|
||||||
|
num, _ = strconv.ParseFloat(raw, 64)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func tolit(json string) (raw string) {
|
||||||
|
for i := 1; i < len(json); i++ {
|
||||||
|
if json[i] <= 'a' || json[i] >= 'z' {
|
||||||
|
return json[:i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
func tostr(json string) (raw string, str string) {
|
||||||
|
// expects that the lead character is a '"'
|
||||||
|
for i := 1; i < len(json); i++ {
|
||||||
|
if json[i] > '\\' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if json[i] == '"' {
|
||||||
|
return json[:i+1], json[1:i]
|
||||||
|
}
|
||||||
|
if json[i] == '\\' {
|
||||||
|
i++
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] > '\\' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if json[i] == '"' {
|
||||||
|
// look for an escaped slash
|
||||||
|
if json[i-1] == '\\' {
|
||||||
|
n := 0
|
||||||
|
for j := i - 2; j > 0; j-- {
|
||||||
|
if json[j] != '\\' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if n%2 == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json[:i+1], unescape(json[1:i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json, json[1:]
|
||||||
|
}
|
||||||
|
|
||||||
// Exists returns true if value exists.
|
// Exists returns true if value exists.
|
||||||
//
|
//
|
||||||
// if gjson.Get(json, "name.last").Exists(){
|
// if gjson.Get(json, "name.last").Exists(){
|
||||||
|
@ -92,17 +389,26 @@ func (t Result) Value() interface{} {
|
||||||
return false
|
return false
|
||||||
case Number:
|
case Number:
|
||||||
return t.Num
|
return t.Num
|
||||||
case Multi:
|
|
||||||
var res = make([]interface{}, len(t.Multi))
|
|
||||||
for i, v := range t.Multi {
|
|
||||||
res[i] = v.Value()
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
case JSON:
|
case JSON:
|
||||||
return t.Raw
|
a, o, vc := t.arrayOrMap(0)
|
||||||
|
if vc == '{' {
|
||||||
|
var m = map[string]interface{}{}
|
||||||
|
for k, v := range o {
|
||||||
|
m[k] = v.Value()
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
} else if vc == '[' {
|
||||||
|
var m = make([]interface{}, 0, len(a))
|
||||||
|
for _, v := range a {
|
||||||
|
m = append(m, v.Value())
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
return nil
|
||||||
case True:
|
case True:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type part struct {
|
type part struct {
|
||||||
|
@ -518,6 +824,9 @@ proc_val:
|
||||||
// the first double-quote has already been read
|
// the first double-quote has already been read
|
||||||
s = i
|
s = i
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] > '\\' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if json[i] == '"' {
|
if json[i] == '"' {
|
||||||
value.Raw = json[s-1 : i+1]
|
value.Raw = json[s-1 : i+1]
|
||||||
value.Str = json[s:i]
|
value.Str = json[s:i]
|
||||||
|
@ -598,14 +907,19 @@ proc_val:
|
||||||
case '}', ']':
|
case '}', ']':
|
||||||
if arrch && parts[depth-1].key == "#" {
|
if arrch && parts[depth-1].key == "#" {
|
||||||
if alogok {
|
if alogok {
|
||||||
result := Result{Type: Multi}
|
var jsons = make([]byte, 0, 64)
|
||||||
|
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(json[alog[j]:], alogkey)
|
||||||
if res.Exists() {
|
if res.Exists() {
|
||||||
result.Multi = append(result.Multi, res)
|
if j > 0 {
|
||||||
|
jsons = append(jsons, ',')
|
||||||
|
}
|
||||||
|
jsons = append(jsons, []byte(res.Raw)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
jsons = append(jsons, ']')
|
||||||
|
return Result{Type: JSON, Raw: string(jsons)}
|
||||||
} else {
|
} else {
|
||||||
return Result{Type: Number, Num: float64(f.count)}
|
return Result{Type: Number, Num: float64(f.count)}
|
||||||
}
|
}
|
||||||
|
@ -689,7 +1003,7 @@ func unescape(json string) string { //, error) {
|
||||||
// The caseSensitive paramater is used when the tokens are Strings.
|
// The caseSensitive paramater is used when the tokens are Strings.
|
||||||
// The order when comparing two different type is:
|
// The order when comparing two different type is:
|
||||||
//
|
//
|
||||||
// Null < False < Number < String < True < JSON < Multi
|
// Null < False < Number < String < True < JSON
|
||||||
//
|
//
|
||||||
func (t Result) Less(token Result, caseSensitive bool) bool {
|
func (t Result) Less(token Result, caseSensitive bool) bool {
|
||||||
if t.Type < token.Type {
|
if t.Type < token.Type {
|
||||||
|
@ -707,17 +1021,6 @@ func (t Result) Less(token Result, caseSensitive bool) bool {
|
||||||
if t.Type == Number {
|
if t.Type == Number {
|
||||||
return t.Num < token.Num
|
return t.Num < token.Num
|
||||||
}
|
}
|
||||||
if t.Type == Multi {
|
|
||||||
for i := 0; i < len(t.Multi) && i < len(token.Multi); i++ {
|
|
||||||
if t.Multi[i].Less(token.Multi[i], caseSensitive) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if token.Multi[i].Less(t.Multi[i], caseSensitive) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(t.Multi) < len(token.Multi)
|
|
||||||
}
|
|
||||||
return t.Raw < token.Raw
|
return t.Raw < token.Raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,32 +116,64 @@ var basicJSON = `{"age":100, "name":{"here":"B\\\"R"},
|
||||||
"firstName": "Elliotte",
|
"firstName": "Elliotte",
|
||||||
"lastName": "Harold",
|
"lastName": "Harold",
|
||||||
"email": "cccc"
|
"email": "cccc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"firstName": 1002.3
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
func TestBasic(t *testing.T) {
|
func TestBasic(t *testing.T) {
|
||||||
|
var mtok Result
|
||||||
|
mtok = Get(basicJSON, "loggy")
|
||||||
|
if mtok.Type != JSON {
|
||||||
|
t.Fatalf("expected %v, got %v", JSON, mtok.Type)
|
||||||
|
}
|
||||||
|
if len(mtok.Map()) != 1 {
|
||||||
|
t.Fatalf("expected %v, got %v", 1, len(mtok.Map()))
|
||||||
|
}
|
||||||
|
programmers := mtok.Map()["programmers"]
|
||||||
|
if programmers.Array()[1].Map()["firstName"].Str != "Jason" {
|
||||||
|
t.Fatalf("expected %v, got %v", "Jason", mtok.Map()["programmers"].Array()[1].Map()["firstName"].Str)
|
||||||
|
}
|
||||||
|
|
||||||
|
if Parse(basicJSON).Get("loggy.programmers").Get("1").Get("firstName").Str != "Jason" {
|
||||||
|
t.Fatalf("expected %v, got %v", "Jason", Parse(basicJSON).Get("loggy.programmers").Get("1").Get("firstName").Str)
|
||||||
|
}
|
||||||
var token Result
|
var token Result
|
||||||
mtok := Get(basicJSON, "loggy.programmers.#.firstName")
|
if token = Parse("-102"); token.Num != -102 {
|
||||||
if mtok.Type != Multi {
|
t.Fatal("expected %v, got %v", -102, token.Num)
|
||||||
t.Fatal("expected %v, got %v", Multi, mtok.Type)
|
|
||||||
}
|
}
|
||||||
if len(mtok.Multi) != 3 {
|
if token = Parse("102"); token.Num != 102 {
|
||||||
t.Fatalf("expected 3, got %v", len(mtok.Multi))
|
t.Fatal("expected %v, got %v", 102, token.Num)
|
||||||
}
|
}
|
||||||
for i, ex := range []string{"Brett", "Jason", "Elliotte"} {
|
if token = Parse("102.2"); token.Num != 102.2 {
|
||||||
if mtok.Multi[i].String() != ex {
|
t.Fatal("expected %v, got %v", 102.2, token.Num)
|
||||||
t.Fatalf("expected '%v', got '%v'", ex, mtok.Multi[i].String())
|
}
|
||||||
|
if token = Parse(`"hello"`); token.Str != "hello" {
|
||||||
|
t.Fatal("expected %v, got %v", "hello", token.Str)
|
||||||
|
}
|
||||||
|
if token = Parse(`"\"he\nllo\""`); token.Str != "\"he\nllo\"" {
|
||||||
|
t.Fatal("expected %v, got %v", "\"he\nllo\"", token.Str)
|
||||||
|
}
|
||||||
|
mtok = Get(basicJSON, "loggy.programmers.#.firstName")
|
||||||
|
if len(mtok.Array()) != 4 {
|
||||||
|
t.Fatalf("expected 4, got %v", len(mtok.Array()))
|
||||||
|
}
|
||||||
|
for i, ex := range []string{"Brett", "Jason", "Elliotte", "1002.3"} {
|
||||||
|
if mtok.Array()[i].String() != ex {
|
||||||
|
t.Fatalf("expected '%v', got '%v'", ex, mtok.Array()[i].String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mtok = Get(basicJSON, "loggy.programmers.#.asd")
|
mtok = Get(basicJSON, "loggy.programmers.#.asd")
|
||||||
if mtok.Type != Multi {
|
if mtok.Type != JSON {
|
||||||
t.Fatal("expected %v, got %v", Multi, mtok.Type)
|
t.Fatal("expected %v, got %v", JSON, mtok.Type)
|
||||||
}
|
}
|
||||||
if len(mtok.Multi) != 0 {
|
if len(mtok.Array()) != 0 {
|
||||||
t.Fatalf("expected 0, got %v", len(mtok.Multi))
|
t.Fatalf("expected 0, got %v", len(mtok.Array()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if Get(basicJSON, "items.3.tags.#").Num != 3 {
|
if Get(basicJSON, "items.3.tags.#").Num != 3 {
|
||||||
t.Fatalf("expected 3, got %v", Get(basicJSON, "items.3.tags.#").Num)
|
t.Fatalf("expected 3, got %v", Get(basicJSON, "items.3.tags.#").Num)
|
||||||
}
|
}
|
||||||
|
@ -201,13 +233,19 @@ func TestBasic(t *testing.T) {
|
||||||
if token.String() != `{"what is a wren?":"a bird"}` {
|
if token.String() != `{"what is a wren?":"a bird"}` {
|
||||||
t.Fatal("expecting '"+`{"what is a wren?":"a bird"}`+"'", "got", token.String())
|
t.Fatal("expecting '"+`{"what is a wren?":"a bird"}`+"'", "got", token.String())
|
||||||
}
|
}
|
||||||
_ = token.Value().(string)
|
_ = token.Value().(map[string]interface{})
|
||||||
|
|
||||||
if Get(basicJSON, "").Value() != nil {
|
if Get(basicJSON, "").Value() != nil {
|
||||||
t.Fatal("should be nil")
|
t.Fatal("should be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
Get(basicJSON, "vals.hello")
|
Get(basicJSON, "vals.hello")
|
||||||
|
|
||||||
|
mm := Parse(basicJSON).Value().(map[string]interface{})
|
||||||
|
fn := mm["loggy"].(map[string]interface{})["programmers"].([]interface{})[1].(map[string]interface{})["firstName"].(string)
|
||||||
|
if fn != "Jason" {
|
||||||
|
t.Fatalf("expecting %v, got %v", "Jason", fn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnescape(t *testing.T) {
|
func TestUnescape(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue