Golang中JSON反序列化遇到问题求助
Golang中JSON反序列化遇到问题求助 我想反序列化这个JSON:
{
"BSR Address": "10.0.3.5",
"228.0.0.0/8": {
"10.0.3.5": {
"Rp Address": "10.0.3.5",
"Rp HoldTime": 65535,
"Rp Priority": 1,
"Hash Val": 840583365
},
"Pending RP count": 100
}
}
但是如果没有JSON标签,它就无法工作,而这些标签是在运行时生成的。
更多关于Golang中JSON反序列化遇到问题求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html
到目前为止你尝试了什么?
通常,对于具有动态键的对象,我会使用 map[string]T;如果值的类型是异构的,我会使用 map[string]interface{}。
func main() {
fmt.Println("hello world")
}
更多关于Golang中JSON反序列化遇到问题求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我需要获取键值以及结构体值,但内部的 map[string]struct 无法正确反序列化。
我也尝试使用了在线 JSON 转 Go 转换器自动生成的结构体,但如果我移除其中的 JSON 标签,它就会失败。
我没有看到任何结构体。我只看到一个 JSON 对象。
如果你确实有一个想要解组到的结构体,你需要给它打上标签。如果你不能打标签,就必须像上面提到的那样,解组到一个更动态的类型。
我目前正在使用移动设备,因此无法轻易给你一个示例。
// 代码示例应放在这里
再次强调,如果你想反序列化到一个结构体中,必须指定所有字段。由于你似乎无法做到这一点,就必须使用一个更动态的根类型。
或者,有方法可以编写比“默认”实现更具体的反序列化器。
这样的实现可以将已知字段存储在结构体的字段中,并将动态字段存储在结构体另一个字段的映射中。
我还没有使用过这种专门的反序列化器,但我见过它们在实际中的应用。
哦,还有另一个非常有用的资源我忘了提,它可以帮你节省时间:尝试将你的 JSON 粘贴到 JSON-to-Go。在处理来自互联网的随机 JSON 时,这总是一个很好的初步排查步骤。 
我尝试了这些结构体:
type RP struct {
RpAddress string `json:"Rp Address"`
RpHoldTime int `json:"Rp HoldTime"`
RpPriority int `json:"Rp Priority"`
HashVal int `json:"Hash Val"`
}
type A struct {
Rpinfo map[string]RP
PendingRPCount int `json:"Pending RP count"`
}
type final struct {
Bsrinfo map[string]A
BSRAddress string `json:"BSR Address"`
}
在Go中处理动态键名的JSON时,可以使用map[string]interface{}或自定义json.RawMessage来解析。以下是两种解决方案:
方案1:使用map[string]interface{}进行通用解析
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonStr := `{
"BSR Address": "10.0.3.5",
"228.0.0.0/8": {
"10.0.3.5": {
"Rp Address": "10.0.3.5",
"Rp HoldTime": 65535,
"Rp Priority": 1,
"Hash Val": 840583365
},
"Pending RP count": 100
}
}`
var data map[string]interface{}
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
panic(err)
}
// 访问BSR Address
bsrAddr := data["BSR Address"].(string)
fmt.Printf("BSR Address: %s\n", bsrAddr)
// 动态访问子网信息
subnetData := data["228.0.0.0/8"].(map[string]interface{})
for key, value := range subnetData {
if key == "Pending RP count" {
count := int(value.(float64))
fmt.Printf("Pending RP count: %d\n", count)
} else {
rpInfo := value.(map[string]interface{})
fmt.Printf("RP %s: %+v\n", key, rpInfo)
}
}
}
方案2:使用json.RawMessage延迟解析
package main
import (
"encoding/json"
"fmt"
)
type RPInfo struct {
RpAddress string `json:"Rp Address"`
RpHoldTime int `json:"Rp HoldTime"`
RpPriority int `json:"Rp Priority"`
HashVal int `json:"Hash Val"`
}
type SubnetData struct {
PendingRPCount int `json:"Pending RP count"`
RPDetails map[string]RPInfo `json:"-"`
}
func main() {
jsonStr := `{
"BSR Address": "10.0.3.5",
"228.0.0.0/8": {
"10.0.3.5": {
"Rp Address": "10.0.3.5",
"Rp HoldTime": 65535,
"Rp Priority": 1,
"Hash Val": 840583365
},
"Pending RP count": 100
}
}`
var raw map[string]json.RawMessage
if err := json.Unmarshal([]byte(jsonStr), &raw); err != nil {
panic(err)
}
// 解析BSR Address
var bsrAddr string
json.Unmarshal(raw["BSR Address"], &bsrAddr)
fmt.Printf("BSR Address: %s\n", bsrAddr)
// 动态解析子网数据
var subnetRaw map[string]json.RawMessage
json.Unmarshal(raw["228.0.0.0/8"], &subnetRaw)
subnetData := SubnetData{}
subnetData.RPDetails = make(map[string]RPInfo)
for key, value := range subnetRaw {
if key == "Pending RP count" {
json.Unmarshal(value, &subnetData.PendingRPCount)
} else {
var rpInfo RPInfo
json.Unmarshal(value, &rpInfo)
subnetData.RPDetails[key] = rpInfo
}
}
fmt.Printf("Pending RP count: %d\n", subnetData.PendingRPCount)
for rpAddr, info := range subnetData.RPDetails {
fmt.Printf("RP %s: %+v\n", rpAddr, info)
}
}
方案3:自定义UnmarshalJSON方法
package main
import (
"encoding/json"
"fmt"
)
type NetworkData struct {
BSRAddress string `json:"BSR Address"`
Subnets map[string]json.RawMessage `json:"-"`
}
func (n *NetworkData) UnmarshalJSON(data []byte) error {
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
// 处理固定字段
if v, ok := raw["BSR Address"]; ok {
json.Unmarshal(v, &n.BSRAddress)
delete(raw, "BSR Address")
}
// 剩余的都是动态子网
n.Subnets = raw
return nil
}
func main() {
jsonStr := `{
"BSR Address": "10.0.3.5",
"228.0.0.0/8": {
"10.0.3.5": {
"Rp Address": "10.0.3.5",
"Rp HoldTime": 65535,
"Rp Priority": 1,
"Hash Val": 840583365
},
"Pending RP count": 100
}
}`
var data NetworkData
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
panic(err)
}
fmt.Printf("BSR Address: %s\n", data.BSRAddress)
for subnet, rawSubnet := range data.Subnets {
fmt.Printf("Subnet %s: %s\n", subnet, string(rawSubnet))
}
}
这些方案都能处理运行时生成的动态键名。第一种方案最简单直接,第二种提供了更好的类型安全,第三种最灵活。根据你的具体需求选择合适的方法。


