Unmarshaling вложенных пользовательских однотипных JSON в Go - PullRequest
0 голосов
/ 17 ноября 2018

С учетом следующего JSON

{
   "some": "value"
   "nested": {
     "some": "diffvalue",
     "nested": {
        "some": "innervalue"
     }
   }
}

, что примерно соответствует этой структуре:

type Envelope struct {
    some     string         `json:"some"`
    nested   InnerEnvelope  `json:"nested"`
}

, где InnerEnvelope: type InnerEnvelope map[string]interface{}

Выполнение простогоjson.Unmarshal([]byte value, &target) здесь не помогает, из-за рекурсивной природы типов исходного JSON.

Я не знаю заранее, насколько глубоко и под какими ключами будут существовать внутренние карты, поэтому я не могу объявить типы заранее..

Идея состоит в том, что использование map[string]interface{} в качестве типа недостаточно хорошо, так как мне нужно, чтобы значения в InnerEnvelope были как-то преобразованы и типизированы.Детали не важны, но изображение, мне нужно привести каждое значение внутри NestedEnvelope типа bool в виде строки, говорящей «true» или «false», в отличие от фактического bool типа.

Я обратился к UnmarshalJSON интерфейсу, чтобы решить эту проблему.Я легко могу сделать это на верхнем уровне следующим образом:

func (m *Envelope) UnmarshalJSON(b []byte) error {
    var stuff noBoolMap
    if err := json.Unmarshal(b, &stuff); err != nil {
        return err
    }
    for key, value := range stuff {
        switch value.(type) {

        case bool:
            stuff[key] = strconv.FormatBool(value.(bool))
        }
    }
    return nil
}

Но так как внутренние json.Unmarshal уже будут иметь внутренние карты, проанализированные как map[string]interface{}, мне нужно было бы еще раз пройти через внутреннийкарты, приведите их к соответствующему типу и выполните мои преобразования значений.

Итак, мой вопрос: в таком случае, как это будет подходить в Go, и предпочтительно делать это за один проход?

Ожидаемый результат примера JSON выше:

Envelope {
     some: string
     nested: InnerEnvelope {
       some: string {
       nested: InnerEnvelope {
         some: string
       }
     }
  }

1 Ответ

0 голосов
/ 17 ноября 2018

Учитывая ваш JSON, вы можете сделать это:

type Envelope struct {
    some     string         `json:"some"`
    nested   json.RawMessage  `json:"nested"`
}

json.RawMessage - довольно скрытый драгоценный камень, и все больше людей, похоже, обращаются к интерфейсу map [string] {}.

Использование json.RawMessage приведет к тому, что вложенный json будет представлен этим RawMessage, который затем вы сможете снова обработать как обычный json (распаковать его в Envelope).

Это более элегантно, чем интерфейс map [string] {}.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...