简体   繁体   English

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

[英]How to get the key value from a json string in Go

I would like to try get the key values from JSON in Go, however I'm unsure how to.我想尝试在 Go 中从 JSON 获取键值,但是我不确定如何。

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.我已经能够使用 simplejson 读取 json 值,但是我无法找到如何获取键值。

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:您可以通过执行以下操作来获取 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]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.请注意,键的顺序不能与它们在 JSON 结构中的顺序相对应。 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 :如果你不想写几十个无用的结构,你可以使用类似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.我只需要一个巨大的 json 响应中的所有值中的一个。

My approach: Simply using a regex over an given string, in this case the JSON formatted string.我的方法:简单地在给定的字符串上使用正则表达式,在这种情况下是 JSON 格式的字符串。

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) "}" "]" (所以基本上任何可以关闭 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.我看到的主要优点是,您不需要关心 JSON 响应的结构,而只需按键查找所需的值。

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:我使用以下内容从 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM