Golang动态解析结构体的实现方法
Golang动态解析结构体的实现方法
type UserMessage struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Data DataType `json:"data" bson:"data"`
}
type DataType struct{
Details []DetailsData `json:"details" bson:"details"`
}
type DetailsData struct{
Name string `json:"name" bson:"name"`
Value []interface{} `json:"value" bson:"value"`
}
示例数据
{"id":"78787871287182", "data":{ "details": [ {"name":"Person","value":"TestName"}, {"name":"PersonRoles","value":[{"name":"DEV","type":"open"},{"name":"UAT","Type":"closed"}]} ] } }
我尝试通过将 DetailsData 中的 Value 设置为 interface{} 和 []interface{} 来进行反序列化。当 value 只是一个字符串时,使用 interface{} 会失败;而当 value 不是数组时,使用 []interface{} 也无法成功反序列化。
更多关于Golang动态解析结构体的实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
实现 json.Unmarshaler 接口,并定义 DetailsData 对象的解析行为。
更多关于Golang动态解析结构体的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中处理动态JSON结构时,可以使用json.RawMessage来延迟解析不确定类型的字段。以下是针对你案例的解决方案:
package main
import (
"encoding/json"
"fmt"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type UserMessage struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Data DataType `json:"data" bson:"data"`
}
type DataType struct {
Details []DetailsData `json:"details" bson:"details"`
}
type DetailsData struct {
Name string `json:"name" bson:"name"`
Value json.RawMessage `json:"value" bson:"value"`
}
// 自定义解析方法
func (d *DetailsData) ParseValue() interface{} {
// 尝试解析为字符串
var strVal string
if err := json.Unmarshal(d.Value, &strVal); err == nil {
return strVal
}
// 尝试解析为对象数组
var objArr []map[string]interface{}
if err := json.Unmarshal(d.Value, &objArr); err == nil {
return objArr
}
// 尝试解析为单个对象
var obj map[string]interface{}
if err := json.Unmarshal(d.Value, &obj); err == nil {
return obj
}
// 返回原始JSON
return string(d.Value)
}
func main() {
jsonData := `{
"id": "78787871287182",
"data": {
"details": [
{
"name": "Person",
"value": "TestName"
},
{
"name": "PersonRoles",
"value": [
{"name": "DEV", "type": "open"},
{"name": "UAT", "Type": "closed"}
]
}
]
}
}`
var userMsg UserMessage
if err := json.Unmarshal([]byte(jsonData), &userMsg); err != nil {
panic(err)
}
// 动态解析每个details的value
for i, detail := range userMsg.Data.Details {
parsedValue := detail.ParseValue()
fmt.Printf("Detail %d - Name: %s, Value: %v\n", i, detail.Name, parsedValue)
// 类型判断示例
switch v := parsedValue.(type) {
case string:
fmt.Printf(" Type: string, Value: %s\n", v)
case []map[string]interface{}:
fmt.Printf(" Type: array of objects, Length: %d\n", len(v))
for _, obj := range v {
fmt.Printf(" Object: %v\n", obj)
}
case map[string]interface{}:
fmt.Printf(" Type: object, Keys: %v\n", v)
default:
fmt.Printf(" Type: unknown, Raw: %s\n", string(detail.Value))
}
}
}
如果需要更灵活的类型处理,可以使用自定义的UnmarshalJSON方法:
type DynamicValue struct {
raw json.RawMessage
parsed interface{}
}
func (dv *DynamicValue) UnmarshalJSON(data []byte) error {
dv.raw = data
// 尝试多种类型解析
var strVal string
if err := json.Unmarshal(data, &strVal); err == nil {
dv.parsed = strVal
return nil
}
var arrVal []interface{}
if err := json.Unmarshal(data, &arrVal); err == nil {
dv.parsed = arrVal
return nil
}
var objVal map[string]interface{}
if err := json.Unmarshal(data, &objVal); err == nil {
dv.parsed = objVal
return nil
}
dv.parsed = nil
return nil
}
func (dv *DynamicValue) Get() interface{} {
return dv.parsed
}
// 在DetailsData中使用
type DetailsData struct {
Name string `json:"name" bson:"name"`
Value DynamicValue `json:"value" bson:"value"`
}
对于MongoDB的BSON序列化,需要实现相应的BSON序列化方法:
func (dv *DynamicValue) UnmarshalBSON(data []byte) error {
// BSON解析逻辑
return json.Unmarshal(data, &dv.raw)
}
func (dv *DynamicValue) MarshalBSON() ([]byte, error) {
return json.Marshal(dv.parsed)
}
这种方法允许你在运行时动态处理不同类型的value字段,同时保持类型安全。

