Проблема Golang с доступом к вложенному массиву JSON после разархивирования

#json #go

# #json #Вперед

Вопрос:

Я все еще нахожусь в процессе обучения Go, но натыкаюсь на стену, когда дело доходит до массивов ответов JSON. Всякий раз, когда я пытаюсь получить доступ к вложенному элементу массива «objects», Go выдает (интерфейс типа {} не поддерживает индексацию)

Что происходит не так и как я могу избежать этой ошибки в будущем?

 package main    

import (
        "encoding/json"
        "fmt"
)    

func main() {
        payload := []byte(`{"query": "QEACOR139GID","count": 1,"objects": [{"ITEM_ID": "QEACOR139GID","PROD_CLASS_ID": "BMXCPGRIPS","AVAILABLE": 19}]}`)
        var result map[string]interface{}
        if err := json.Unmarshal(payload, amp;result); err != nil {
            panic(err)
        }        

        fmt.Println(result["objects"]["ITEM_ID"])    

}
 

http://play.golang.org/p/duW-meEABJ

редактировать: исправлена ссылка

Комментарии:

1. ваш пример работает для меня…

2. @fabrizioM, пример в play.golang.org это не то же самое, что код, указанный в вопросе.

3. Исправлено. Извините за это.

Ответ №1:

Как указано в ошибке, переменные интерфейса не поддерживают индексацию. Вам нужно будет использовать утверждение типа для преобразования в базовый тип.

При декодировании в interface{} переменную модуль JSON представляет массивы в виде []interface{} фрагментов, а словари — в виде map[string]interface{} карт.

Без проверки ошибок вы могли бы углубиться в этот JSON с помощью чего-то вроде:

 objects := result["objects"].([]interface{})
first := objects[0].(map[string]interface{})
fmt.Println(first["ITEM_ID"])
 

Эти утверждения типа будут паниковать, если типы не совпадают. Вы можете использовать форму с двумя возвратами, вы можете проверить наличие этой ошибки. Например:

 objects, ok := result["objects"].([]interface{})
if !ok {
    // Handle error here
}
 

Однако, если JSON соответствует известному формату, лучшим решением было бы декодировать в структуру. Учитывая данные в вашем примере, может быть выполнено следующее:

 type Result struct {
    Query   string `json:"query"`
    Count   int    `json:"count"`
    Objects []struct {
        ItemId      string `json:"ITEM_ID"`
        ProdClassId string `json:"PROD_CLASS_ID"`
        Available   int    `json:"AVAILABLE"`
    } `json:"objects"`
}
 

Если вы декодируете в этот тип, вы можете получить доступ к идентификатору элемента как result.Objects[0].ItemId .

Комментарии:

1. Я буквально только что набрал тот же ответ. Отложено, потому что мне пришлось нести продукты 🙂

2. Для дальнейшего использования вот рабочий пример воспроизведения: play.golang.org/p/iYjrB-72u5

3. Спасибо за понимание работы с вложенной структурой JSON!

4. ПРИВЕТ, Джеймс Хенстридж, введите пример struct { text []string } введите Result struct {Количество строк запроса int Objects []struct {Строка идентификатора элемента } }

Ответ №2:

Для тех, кто, возможно, ищет подобное решение, как я, https://github.com/Jeffail/gabs предлагает лучшее решение.

Я привожу пример здесь.

 package main

import (
    "encoding/json"
    "fmt"

    "github.com/Jeffail/gabs"
)

func main() {
    payload := []byte(`{
        "query": "QEACOR139GID",
        "count": 1,
        "objects": [{
            "ITEM_ID": "QEACOR139GID",
            "PROD_CLASS_ID": "BMXCPGRIPS",
            "AVAILABLE": 19, 
            "Messages": [ {
                    "first": {
                        "text":  "sth, 1st"
                    }
                },
                {
                        "second": {
                        "text": "sth, 2nd"
                    }
              }
            ]
        }]
    }`)

    fmt.Println("Use gabs:")
    jsonParsed, _ := gabs.ParseJSON(payload)
    data := jsonParsed.Path("objects").Data()
    fmt.Println("  Fetch Data: ")
    fmt.Println("    ", data)
    children, _ := jsonParsed.Path("objects").Children()
    fmt.Println("  Children Array from "Objects": ")
    for key, child := range children {
        fmt.Println("    ", key, ": ", child)
        children2, _ := child.Path("Messages").Children()
        fmt.Println("    Children Array from "Messages": ")
        for key2, child2 := range children2 {
            fmt.Println("      ", key2, ": ", child2)
        }
    }
}