简体   繁体   中英

Couldn't unmarshal xml to a dynamically created struct using reflection in Golang

This is my code for parsing xml. At the end of the function, I should have values of fields of a struct in the values slice.

func FindAttrs(attrs []Tag, errorChan chan<- error) {
    var tableFields []reflect.StructField
    for _, v := range attrs {
        tableFields = append(tableFields, reflect.StructField{
            Name:      strings.Title(v.Name),
            Type:      reflect.TypeOf(""),
            Tag:       reflect.StructTag(fmt.Sprintf(`xml:"%v,attr"`, v.Name)),
            Offset:    0,
            PkgPath:   "utility",
            Index:     nil,
            Anonymous: false,
        })
    }
    unmarshalStruct := reflect.Zero(reflect.StructOf(tableFields))
    err := xml.Unmarshal(ReadBytes(errorChan), &unmarshalStruct)
    HandleError(err, "Error parse config", false, errorChan)
    values := make([]interface{}, unmarshalStruct.NumField())
    for i := 0; i < unmarshalStruct.NumField(); i++ {
        values[i] = unmarshalStruct.Field(0).Interface()
    }
}

But, it panics with the following message:

reflect.Value.Interface: cannot return value obtained from unexported field or method

I call it with:

utility.FindAttrs([]utility.Tag{
        {"name", reflect.String}, {"isUsed", reflect.String},
    }, errorChan)

And my xml is <configuration name="mur" isUsed="mur"/>

Need to make a pointer to struct instead of a value and pass pointer's value, which can by retrieved Interface() function, to Unmarshal instead of it itself.

var tableFields []reflect.StructField
    for _, v := range attrs {
        tableFields = append(tableFields, reflect.StructField{
            Name: strings.Title(v.Name),
            Type: reflect.TypeOf(""),
            Tag:  reflect.StructTag(fmt.Sprintf(`xml:"%v,attr"`, v.Name)),
        })
    }

    rv := reflect.New(reflect.StructOf(tableFields)) // initialize a pointer to the struct

    v := rv.Interface() // get the actual value
    err := xml.Unmarshal([]byte(`<configuration name="foo" isUsed="bar"/>`), v)
    if err != nil {
        panic(err)
    }

    rv = rv.Elem() // dereference the pointer
    values := make([]interface{}, rv.NumField())
    for i := 0; i < rv.NumField(); i++ {
        values[i] = rv.Field(i).Interface()
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM