1

I want to parse an xml attribute as an iota enum type (int) in go.

Below you can see what I tried but this does not work because the address of enum variables can't be taken.

type EnumType int
const (
    EnumUnknown EnumType = iota
    EnumFoo
    EnumBar
)

func (E *EnumType) UnmarshalXMLAttr(attr xml.Attr) error {
    switch attr.Value {
    case "foo":
        E = &EnumFoo
    case "bar":
        E = &EnumBar
    default:
        E = &EnumUnknown
    }
    return nil
}


// Example of how the unmarshal could be called:
type Tag struct {
    Attribute EnumType `xml:"attribute,attr"`
}

func main() {
    tag := &Tag{}
    xml.Unmarshal([]byte("<tag attribute=\"foo\"/>"), tag)
}

Any other way to make UnmarshalXMLAttr work with int types?

Update: I know I can solve this by adding the UnmarshalXML method to Tag but I want to avoid this if possible because I have a lot of different tags with a lot of different attributes but only a few custom typed attributes. So implementing UnmarshalXML methods for each tag would not be preferred.

David
  • 31
  • 4
  • 1
    You do not need the struct in your answer, instead in the enum's unmarshalxmlattr do `*E = EnumFoo`, not `E = &EnumFoo`. Doing `E = &EnumFoo` you are essentially overwriting the pointer value, not the value the pointer points to, and that's why outside of the method the change is not visible since outside the method the pointer value is the same. That is, a method cannot *replace* it's receiver, it can however modify the memory pointed to by the receiver. – mkopriva May 27 '19 at 08:35
  • https://play.golang.com/p/zvs0_iyVq5n – mkopriva May 27 '19 at 08:54

1 Answers1

2

I solved the problem by wrapping the int in a struct.

type EnumType int
const (
    EnumUnknown EnumType = iota
    EnumFoo
    EnumBar
)
type EnumContainer struct {
    Value EnumType
}

func (E *EnumContainer) UnmarshalXMLAttr(attr xml.Attr) error {
    switch attr.Value {
    case "foo":
        E.Value = EnumFoo
    case "bar":
        E.Value = EnumBar
    default:
        E.Value = EnumUnknown
    }
    return nil
}


// Example of how the unmarshal could be called:
type Tag struct {
    Attribute EnumContainer `xml:"attribute,attr"`
}

func main() {
    tag := &Tag{}
    xml.Unmarshal([]byte("<tag attribute=\"foo\"/>"), tag)

Is there a "more elegant" way or should I be happy with what I now have?

David
  • 31
  • 4