Golang Не выделяет определенный объект во вложенном JSON

# #arrays #json #go #unmarshalling

Вопрос:

какова наилучшая практика для удаления определенной части большого JSON со статическими именами свойств в GO?

моя карта JSON выглядит так

 {
    "top_view" : {
       "@self" : "https://generic.com",
           "graph" : {
              "nodes" : [ { } ],
              "relations" : [ { } ]
                     },
         "view_status" : {}
                 }
}
 

и мне нужно только получить массив узлов

Вот что я получил до сих пор,

https://play.golang.org/p/btfRojEGqUu

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

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

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

2. Объявите типы Go с минимальной структурой, необходимой для получения нужной вам детали. Разархивируйте документ JSON и выберите нужную часть. var data = struct { TopView struct { Self struct { Graph Graph } `json:"@self"` } `json:"top_view"` }

3. На мой взгляд, лучший способ-это просто разархивировать соответствующую структуру, а затем игнорировать нежелательные части. Например: play.golang.org/p/y_9IdVpZdqW

Ответ №1:

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

 type Whole struct {
    TopView struct {
        Self  string `json:"@self"`
        Graph struct {
            Nodes []Node `json:"nodes"`
        } `json:"graph"`
    } `json:"top_view"`
}
 

Затем маршалируйте узел

 var whole Whole

err := json.Unmarshal([]byte(jsonResp), amp;whole)
 

Вот рабочий код :
https://play.golang.org/p/5WvPocce_vh

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

1. спасибо, мне очень понравилось это элегантное решение!

Ответ №2:

Вы можете удалить все данные JSON без какого-либо конкретного типа, определенного в go коде. Использование type assertion и type switch детализация данных, просто не обработанных.

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

 package main

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {
    jsonResponse := `{
        "top_view" : {
           "@self" : "https://generic.com",
               "graph" : {
                  "nodes" : [ {
                    "@self" : "https://generic.com:443",
                    "id" : "1;;45d554600be28ee49c99d26e536225ea;;461ff354437881f6b5973d4af366b91c;;4c0f2cc8e29a4fe09240b2a0c311508d",
                    "ci" : {
                       "id" : "4c0f2cc8e29a4fe09240b2a0c311508d",
                       "name" : "NOICE",
                       "type" : "ci_collection",
                       "type_label" : "CiCollection",
                       "icon" : "/logical_group_32.svg"
                    },
                    "has_children" : true
                 }, {
                    "@self" : "https://generic.com:443hjkhk",
                    "id" : "1;;45d554600be28ee49c99d26e536225ea;;4e22910a478bf6939aed36fef22dc79e;;4a7788eeecbbeee3a8bb3189ba67f269",
                    "ci" : {
                       "id" : "4a7788eeecbbeee3a8bb3189ba67f269",
                       "name" : "NOTNOICE",
                       "type" : "ci_collection",
                       "type_label" : "CiCollection",
                       "icon" : "/logical_group_32.svg"
                    },
                    "has_children" : true
                 }, {
                    "@self" : "https://generic.com:443/fghfgh",
                    "id" : "1;;45d554600be28ee49c99d26e536225ea;;461ff354437881f6b5973d4af366b91c;;4c0f2cc8e29a4fe09240b2a0c311508d;;40b8b314821d01ac874f7209c228ab8f",
                    "ci" : {
                       "id" : "40b8b314821d01ac874f7209c228ab8f",
                       "name" : "NOICE",
                       "type" : "ci_collection",
                       "type_label" : "CiCollection",
                       "icon" : "/logical_group_32.svg"
                    },
                    "has_children" : true
                 }, {
                    "@self" : "https://generic.com:443/gfhgh",
                    "id" : "1;;45d554600be28ee49c99d26e536225ea;;4a208e0deee006668bb3cfab6541a869;;4bd30d48bc1c81b398e17435ba519f2d;;4a1c671cefd3b5b9931b4312382ff2e4",
                    "ci" : {
                       "id" : "4a1c671cefd3b5b9931b4312382ff2e4",
                       "name" : "AAA",
                       "type" : "ci_collection",
                       "type_label" : "CiCollection",
                       "icon" : "/logical_group_32.svg"
                    },
                    "has_children" : true
                 } ],
                  "relations" : [ { } ]
                         },
             "view_status" : {}
                     }
    }`

    var res interface{}
    err := json.Unmarshal([]byte(jsonResponse), amp;res)
    if err != nil {
        log.Fatal(err)
    }

    parseArbitoryJSONObject(res)
}

func parseArbitoryJSONObject(jsonObject interface{}) {
    data := jsonObject.(map[string]interface{})

    for k, v := range data {
        switch val := v.(type) {
        case string:
            fmt.Println(k, "is string:", val)
        case float64:
            fmt.Println(k, "is float64", val)
        case bool:
            fmt.Println(k, "is boolean", val)
        case []interface{}:
            fmt.Println(k, "is an array:")
            for i, u := range val {
                fmt.Println(i, u)
            }
        case map[string]interface{}:
            fmt.Println(k, "is an map[string]interface{}:")
            parseArbitoryJSONObject(val)
        default:
            fmt.Println(k, "is of a type I don't know how to handle")
        }
    }
}
 

Здесь json.Unmarshal используется empty interface то, что может содержать любое значение. И функция parseArbitoryJSONObject() используется type assertion для облегчения извлечения значений из незафиксированных данных.

Это то type switch место, где вам, возможно, потребуется дополнительно поместить или изменить логику, чтобы получить нужный элемент из незафиксированного объекта JSON.

ниже приведена ссылка на фрагмент кода go-playground для вашей справки:

https://play.golang.org/p/VUJsSXxSfVG