I would like to try get the key values from JSON in Go, however I'm unsure how to.
I've been able to use simplejson to read json values, however I've not been able to find out how to get the key values.
Would anyone be able to point me in the right direction and/or help me?
Thank you!
You can get the top-level keys of a JSON structure by doing:
package main
import (
"encoding/json"
"fmt"
)
// your JSON structure as a byte slice
var j = []byte(`{"foo":1,"bar":2,"baz":[3,4]}`)
func main() {
// a map container to decode the JSON structure into
c := make(map[string]json.RawMessage)
// unmarschal JSON
e := json.Unmarshal(j, &c)
// panic on error
if e != nil {
panic(e)
}
// a string slice to hold the keys
k := make([]string, len(c))
// iteration counter
i := 0
// copy c's keys into k
for s, _ := range c {
k[i] = s
i++
}
// output result to STDOUT
fmt.Printf("%#v\n", k)
}
Note that the order of the keys must not correspond to the their order in the JSON structure. Their order in the final slice will even vary between different runs of the exact same code. This is because of how map iteration works.
If you don't feel like writing tens of useless structs, you could use something like https://github.com/tidwall/gjson :
gjson.Get(
`{"object": {"collection": [{"items": ["hello"]}]}}`,
"object.collection.items.0",
) // -> "hello"
Plus some weird-useful querying tricks .
Even though the question is old and solved in different ways, I came across an similiar problem and didn't find an easy solution. I only needed 1 of all the values in a huge json-response.
My approach: Simply using a regex over an given string, in this case the JSON formatted string.
The plain string gets filtered for a given key and returns only the value for the given key via this method
// extracts the value for a key from a JSON-formatted string
// body - the JSON-response as a string. Usually retrieved via the request body
// key - the key for which the value should be extracted
// returns - the value for the given key
func extractValue(body string, key string) string {
keystr := "\"" + key + "\":[^,;\\]}]*"
r, _ := regexp.Compile(keystr)
match := r.FindString(body)
keyValMatch := strings.Split(match, ":")
return strings.ReplaceAll(keyValMatch[1], "\"", "")
}
Regarding the given pattern, I didn't test all case, but it's scanning for a string like this double quote, the name of the key, double quote, an semicolon and any char sequence except "," ";""}" "]" (so basically anything that could close a key value pair in the syntax of json)
Example:
jsonResp := "{\"foo\":\"bar\"}"
value := extractValue(jsonResp, "foo")
fmt.Println(value)
would simple return bar
The main advantage I see, that you don't need to care about the structure of the JSON-response, but go just for the value you need by key.
Note: I think it's only possible to grab the value of the first matched key. But you can always modify the method. It just makes use of the regex-technology.
I used the following to grab nested keys from JSON:
import (
"bytes"
"encoding/json"
"errors"
"io"
"sort"
)
func keys(b []byte) ([]string, error) {
dec := json.NewDecoder(bytes.NewBuffer(b))
// store unique keys
kmap := make(map[string]struct{})
// is the next Token a key?
var key bool
// keep track of both object and array parents with a slice of bools:
// - an object parent is true, an array parent is false
parents := make([]bool, 0, 10)
for {
t, err := dec.Token()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
del, ok := t.(json.Delim)
if ok {
if del == '{' {
// push an object parent
parents = append(parents, true)
}
if del == '[' {
// push an array parent
parents = append(parents, false)
}
if del == '}' || del == ']' {
if len(parents) == 0 {
return nil, errors.New("bad json: unexpected } or ] delim")
}
// pop the last parent
parents = parents[:len(parents)-1]
}
if len(parents) > 0 && parents[len(parents)-1] {
// if we are within an object, the next token must be a key
key = true
} else {
// otherwise we are in an array, and the next token is an array entry
key = false
}
continue
}
if key {
str, ok := t.(string)
if !ok {
return nil, errors.New("bad json: keys must be strings")
}
kmap[str] = struct{}{}
// if this is a key, then the next token is the value
key = false
} else if len(parents) > 0 && parents[len(parents)-1] {
// if this is a value, and we are within an object, then the next token is a new key
key = true
}
}
// now turn our map of keys into a sorted slice
ret := make([]string, len(kmap))
var i int
for k := range kmap {
ret[i] = k
i++
}
sort.Strings(ret)
return ret, nil
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.