1

There's a struct:

type S struct {
  Value string `xml:"value,attr"`
}

I want to encode the struct to an XML file. However, I want the attribute name of Value to be different in each file:

s1 := S{
  Value: "One"
}

should encode to:

<S value="One"></S>

and

s2 := S{
  Value: "Two"
}

should encode to:

<S category="Two"></S>

So, I need either to change the XML element name somehow, or change the tag on the field. Is this possible?

I checked reflect (https://golang.org/pkg/reflect/#Value.FieldByName), but since FieldByName returns a value type and there are no Set methods, I don't think it's possible to use reflection.

Kiril
  • 6,009
  • 13
  • 57
  • 77
  • possible duplicate of [Golang marshal dynamic xml element name](http://stackoverflow.com/questions/26867417/golang-marshal-dynamic-xml-element-name) – Ainar-G Jun 19 '15 at 14:25
  • :) Nice, I asked that question a few months ago, but that was the other way around then. Now I need to set the name of a field. I assume I need to wrap every member of my struct into a new struct, and supply the xml.Name. – Kiril Jun 19 '15 at 14:32
  • Yes, you either use different types for different tags, or use `XMLName`, or create a custom marshaler that builds the XML based on some parameter of the struct. – Ainar-G Jun 19 '15 at 14:46
  • Ok I see, but I can't make it work for attributes (see edit, because of duplicate vote). How would it work for them? – Kiril Jun 19 '15 at 14:48

1 Answers1

2

(I don't know why did the other person delete their answer, but here's mine.)

You can either use a combination of ,attr and ,omitempty

type S struct {
    Value    string `xml:"value,attr,omitempty"`
    Category string `xml:"category,attr,omitempty"`
}

(playground: http://play.golang.org/p/C9tRlA80RV) or create a custom xml.MarshalerAttr

type S struct {
    Value Val `xml:",attr"`
}

type Val struct{ string }

func (v Val) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
    if v.string == "One" {
        return xml.Attr{Name: xml.Name{Local: "value"}, Value: v.string}, nil
    }

    return xml.Attr{Name: xml.Name{Local: "category"}, Value: v.string}, nil
}

(playground: http://play.golang.org/p/a1Wd2gonb_).

The first approach is easier but less flexible, and also makes the struct bigger. The second approach is slightly more complex, but also more robust and flexible.

Ainar-G
  • 34,563
  • 13
  • 93
  • 119
  • Can I put ```xml:",attr"``` on the `type Val struct` definition? – Kiril Jun 19 '15 at 15:43
  • No, but you can [create a wrapper and embed it](http://play.golang.org/p/pfXzhhekvN). I personally wouldn't do it, since it would make the code less explicit, but I don't know your use case, so it's up to you. – Ainar-G Jun 19 '15 at 15:47