#json #list #go #struct
# #json #Список #Вперед #структура
Вопрос:
Я работаю с некоторыми API-интерфейсами от моего Fritz!Box router, я бы хотел разобрать ответ json в приличной структуре, просто нужно найти хороший способ сделать это.
Иногда в ответе API параметром WLan является bool, в других случаях это объект этого типа
// WLan contains info about the Wireless Lan
type WLan struct {
Txt string `json:"txt"`
Led string `json:"led"`
Title string `json:"title"`
Link string `json:"link"`
Tooltip string `json:"tooltip"`
}
Если вам нужна дополнительная информация о коде, вы можете использовать репозиторий github.
Мне нужно добавить логический параметр wlan, я попытался дублировать структуру «Data» и изменить имя, но это решение звучит для меня очень плохо.
Wlan содержится в этой структуре:
// Data contains data about the Fritz!Box
type Data struct {
NasLink string `json:"naslink"`
FritzOS FritzOS `json:"fritzos"`
Webdav int `json:"webdav,string"`
Manual string `json:"MANUAL_URL"`
Language string `json:"language"`
AVM string `json:"AVM_URL"`
USBConnect string `json:"usbconnect"`
Foncalls Foncalls `json:"foncalls"`
VPN VPN `json:"vpn"`
Internet Internet `json:"internet"`
DSL DSL `json:"dsl"`
ServicePortalURL string `json:"SERVICEPORTAL_URL"`
Comfort Comfort `json:"comfort"`
Changelog Changelog `json:"changelog"`
TamCalls TamCalls `json:"tamcalls"`
Lan External `json:"lan"`
USB External `json:"usb"`
FonNum External `json:"fonnum"`
NewsURL string `json:"NEWSLETTER_URL"`
Net Net `json:"net"`
Dect External `json:"dect"`
WLan WLan `json:"wlan"`
//Wlan bool `json:"wlan"` # This is the other "case"
}
Комментарии:
1. Используется ли это в другой структуре? Если это так, включите также включающую структуру. Это можно решить несколькими способами, но вам нужно уточнить, что вы хотите, после завершения демаршализации.
2. Да, WLan содержится в данных. Данные разархивируют имя «wlan» на WLan, но иногда вместо объекта json используется значение bool. В любом случае вы можете увидеть полный исходный код на github.
Ответ №1:
Я не знаю, хорошее ли это решение, я все еще новичок, но в любом случае, вы могли бы использовать json.RawMessage
и «отложить» разборку wlan
свойства в одно из двух отдельных полей структуры. например:
package main
import (
"encoding/json"
"fmt"
)
// Data contains data about the Fritz!Box. (other fields omitted for brevity)
type Data struct {
Language string `json:"language"`
NewsURL string `json:"NEWSLETTER_URL"`
WLanRaw *json.RawMessage `json:"wlan"`
WLanBool bool `json:"-"`
WLanInfo *WLanInfo `json:"-"`
}
// WLanInfo contains infos about the Wireless Lan
type WLanInfo struct {
Txt string `json:"txt"`
Led string `json:"led"`
Title string `json:"title"`
Link string `json:"link"`
Tooltip string `json:"tooltip"`
}
func UnmarshalData(raw []byte, data *Data) error {
if err := json.Unmarshal(raw, data); err != nil {
return err
}
switch string(*data.WLanRaw) {
case "true", "false":
json.Unmarshal(*data.WLanRaw, amp;data.WLanBool)
default:
if err := json.Unmarshal(*data.WLanRaw, amp;data.WLanInfo); err != nil {
return err
}
}
return nil
}
func main() {
jsonBool := []byte(`
{
"language": "it",
"NEWSLETTER_URL": "https://example.com/news",
"wlan": true
}`)
jsonInfo := []byte(`
{
"language": "it",
"NEWSLETTER_URL": "https://example.com/news",
"wlan": {
"txt": "footxt",
"led": "fooled",
"title": "hello",
"link": "bar",
"tooltip": "baz"
}
}`)
// error handling omitted
var dataBool Data
UnmarshalData(jsonBool, amp;dataBool)
fmt.Printf("% vnn", dataBool)
var dataInfo Data
UnmarshalData(jsonInfo, amp;dataInfo)
fmt.Printf("% v % vn", dataInfo, dataInfo.WLanInfo)
}
$ go build fritz.go
$ ./fritz
{Language:it NewsURL:https://example.com/news WLanRaw:0xc0000a4060 WLanBool:true WLanInfo:<nil>}
{Language:it NewsURL:https://example.com/news WLanRaw:0xc0000a4080 WLanBool:false WLanInfo:0xc0000b0000} amp;{Txt:footxt Led:fooled Title:hello Link:bar Tooltip:baz}
$
Комментарии:
1. Может быть решением, но вызовет проблемы, когда кто-то проверяет свойство «bool», поскольку оно всегда будет false
2. @LucaDametto это «всегда
false
«, когдаwlan
свойство является объектом в json. ну,WLanBool
должно проверяться только в том случае, еслиWLanInfo
==nil
. довольно некрасиво, я знаю…3. Ммм, может быть решением. Я постараюсь реализовать ваш пример.
Ответ №2:
Вы могли бы реализовать интерфейсы json.Unmarshaler
and json.Marshaler
.
type WLan struct {
Bool *bool `json:"-"`
Txt string `json:"txt"`
Led string `json:"led"`
Title string `json:"title"`
Link string `json:"link"`
Tooltip string `json:"tooltip"`
}
// implements json.Unmarshaler
func (w *WLan) UnmarshalJSON(data []byte) error {
if len(data) > 0 amp;amp; (data[0] == 't' || data[0] == 'f') { // seems to be a bool
w.Bool = new(bool)
return json.Unmarshal(data, w.Bool)
}
if len(data) > 1 amp;amp; data[0] == '{' amp;amp; data[len(data)-1] == '}' { // it's an object
// type W and the conversion (*W)(w) are required to
// prevent encoding/json from invoking the UnmarshalJSON
// method recursively causing a stack overflow
type W WLan
return json.Unmarshal(data, (*W)(w))
}
return nil // or error, up to you
}
// implements json.Marshaler
func (w WLan) MarshalJSON() ([]byte, error) {
if w.Bool != nil {
return json.Marshal(*w.Bool)
}
// Same as with UnmarshalJSON, type W and the conversion W(w) are
// required to prevent encoding/json from invoking the MarshalJSON
// method recursively causing a stack overflow
type W WLan
return json.Marshal(W(w))
}