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

2 回复

实现 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字段,同时保持类型安全。

回到顶部