如何从Go中的json字符串获取键值

时间:2013-07-03 15:58:16

标签: json go

我想尝试从Go中获取JSON中的键值,但是我不确定如何。

我已经能够使用simplejson来读取json值,但是我无法找到如何获取键值。

有人能指出我正确的方向和/或帮助我吗?

谢谢!

4 个答案:

答案 0 :(得分:9)

您可以通过执行以下操作获取JSON结构的顶级键:

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]interface{})

    // 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)

}

请注意,键的顺序不得与JSON结构中的顺序相对应。它们在最终切片中的顺序甚至会在完全相同的代码的不同运行之间变化。这是因为地图迭代的工作原理。

答案 1 :(得分:4)

还有这个令人难以置信的图书馆:https://github.com/jmoiron/jsonq

它允许您通过调用:

从JSON获取嵌套值
// data["subobj"]["subarray"]["array"][0] -> "hello"
jq.String("subobj", "subsubobj", "array", "0")

答案 2 :(得分:3)

尽管这个问题很老,并且以不同的方式解决了,但我遇到了一个类似的问题,却没有找到简单的解决方案。我只需要一个巨大的json-response中的所有值之一即可。

我的方法:在给定的字符串上使用正则表达式,在这种情况下为JSON格式的字符串。

通过给定键过滤纯字符串,并通过此方法仅返回给定键的值

// 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], "\"", "")
}

关于给定的模式,我没有测试所有情况,但是它正在扫描这样的字符串 双引号,键名,双引号,分号和除“,”,“;”以外的任何字符序列“}”“]”(基本上所有可以关闭json语法中的键值对的东西)

示例:

jsonResp := "{\"foo\":\"bar\"}"    
value := extractValue(jsonResp, "foo")
fmt.Println(value)

将简单返回 bar

我看到的主要优点是,您不必关心JSON响应的结构,而只需按键即可获得所需的值。

注意:我认为只能获取第一个匹配键的值。但是您始终可以修改该方法。它只是利用了正则表达式技术。

答案 3 :(得分:0)

我使用以下方法从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
}