douman9420
douman9420
2019-03-06 01:09
浏览 278

检查JSON是对象还是数组

Is there a simple way in Go to check whether given JSON is either an Object {} or array []?

The first thing that comes to mind is to json.Unmarshal() into an interface, and then see if it becomes a map, or a slice of maps. But that seems quite inefficient.

Could I just check if the first byte is a { or a [? Or is there a better way of doing this that already exists.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • duancuan7057
    duancuan7057 2019-03-06 01:40
    已采纳

    Use the following the following to detect if JSON text in the []byte value data is an array or object:

     // Get slice of data with optional leading whitespace removed.
     // See RFC 7159, Section 2 for the definition of JSON whitespace.
     x := bytes.TrimLeft(data, " \t
    ")
    
     isArray := len(x) > 0 && x[0] == '['
     isObject := len(x) > 0 && x[0] == '{'
    

    This snippet of code handles optional leading whitespace and is more efficient than unmarshalling the entire value.

    Because the top-level value in JSON can also be a number, string, boolean or nil, it's possible that isArray and isObject both evaluate to false. The values isArray and isObject can also evaluate to false when the JSON is invalid.

    点赞 评论
  • doulu4233
    doulu4233 2019-03-06 03:17

    Use a type switch to determine the type. This is similar to Xay's answer, but simpler:

    var v interface{}
    if err := json.Unmarshal(data, &v); err != nil {
        // handle error
    }
    switch v := v.(type) {
    case []interface{}:
        // it's an array
    case map[string]interface{}:
        // it's an object
    default:
        // it's something else
    }
    
    点赞 评论
  • dongzhao4036
    dongzhao4036 2019-03-06 07:09

    Do step-by-step parsing of your JSON, using json.Decoder. This has the advantage over the other answers of:

    1. Being more efficient than decoding the entire value
    2. Using the official JSON parsing rules, and generating standard errors if you get invalid input.

    Note, this code isn't tested, but should be enough to give you the idea. It can also be easily expanded to check for numbers, booleans, or strings, if desired.

    type jsonType(in io.Reader) (string, error) {
        dec := json.NewDecoder(in)
        // Get just the first valid JSON token from input
        t, err := dec.Token()
        if err != nil {
            return "", err
        }
        if d, ok := t.(json.Delim); ok {
            // The first token is a delimiter, so this is an array or an object
            switch (d) {
            case "[":
                return "array", nil
            case "{":
                return "object", nil
            default: // ] or }
                return nil, errors.New("Unexpected delimiter")
            }
        }
        return nil, errors.New("Input does not represent a JSON object or array")
    }
    

    Note that this consumed the first few bytes of in. It is an exercise for the reader to make a copy, if necessary. If you're trying to read from a byte slice ([]byte), convert it to a reader first:

    t, err := jsonType(bytes.NewReader(myValue))
    
    点赞 评论

相关推荐