Проверьте, является ли JSON Object или Array - PullRequest
4 голосов
/ 06 марта 2019

Есть ли в Go простой способ проверить, является ли данный JSON объектом {} или массивом []?

Первое, что приходит на ум, - это json.Unmarshal() в интерфейс, а затем посмотреть, станет ли он картой или частью карты. Но это кажется совершенно неэффективным.

Могу ли я просто проверить, является ли первый байт { или [? Или есть лучший способ сделать это, который уже существует.

Ответы [ 3 ]

7 голосов
/ 06 марта 2019

Используйте следующее, чтобы определить, является ли текст JSON в значении []byte data массивом или объектом:

 // 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\r\n")

 isArray := len(x) > 0 && x[0] == '['
 isObject := len(x) > 0 && x[0] == '{'

Этот фрагмент кода обрабатывает необязательный начальный пробел и является более эффективным, чемunmarshalling все значение.

Поскольку значением верхнего уровня в JSON также может быть число, строка, логическое значение или nil, возможно, что и isArray, и isObject оба оцениваются как ложные.Значения isArray и isObject также могут принимать значение false, если JSON является недействительным.

2 голосов
/ 06 марта 2019

Выполните пошаговый анализ вашего JSON, используя json.Decoder. Это имеет преимущество перед другими ответами:

  1. Быть более эффективным, чем декодировать все значение
  2. Использование официальных правил синтаксического анализа JSON и генерация стандартных ошибок, если вы получили неверный ввод.

Обратите внимание, этот код не тестировался, но его должно быть достаточно, чтобы дать вам идею. При желании его также можно легко развернуть для проверки чисел, логических значений или строк.

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")
}

Обратите внимание, что потребляет первые несколько байтов in. Это упражнение для читателя сделать копию, если это необходимо. Если вы пытаетесь читать из байтового фрагмента ([]byte), сначала преобразуйте его в считыватель:

t, err := jsonType(bytes.NewReader(myValue))
2 голосов
/ 06 марта 2019

Используйте переключатель типа для определения типа.Это похоже на ответ Xay, но проще:

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
}
...