GoLang: Refactoring xml tag definition in struct

type Social struct {
    XMLName  xml.Name `xml:"social"`
    Facebook string   `xml:"facebook"`
    Twitter  string   `xml:"twitter"`
    Youtube  string   `xml:"youtube"`
}

In the above example I have the xml:"facebook" reused in multiple structs. I would like to know if I can extract it to a constant and reference it in all structs.

Or is that how you have to define the struct I read through the specs/documentations and did not find any specific way to achieve this.

Is it possible?

PS: My intention was to reduce the duplicate code as it is easy to mistype when you create a new struct (as it had happened to me few times).

Upvotes: 1

Views: 479

Answers (2)

icza
icza

Reputation: 418745

It's not a headache to repeat a tag whenever you need it. Note that the spec does not allow you to use constants or variables when defining tags for struct fields. The struct tag can only be a string literal. Quoting from Spec: Struct types:

StructType    = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag           = string_lit .

One way to "outsource" the tag definition would be to "outsource" the whole struct field into another struct, and have Social embed that struct.

For example:

type Social struct {
    XMLName xml.Name `xml:"social"`
    HasFacebook
    Twitter string `xml:"twitter"`
    Youtube string `xml:"youtube"`
}

type HasFacebook struct {
    Facebook string `xml:"facebook"`
}

And now you can reuse it in other types / structs:

type Social2 struct {
    HasFacebook
    Linkedin string `xml:"linkedin"`
}

Testing both types (Social and Social2):

func main() {
    var s *Social
    if err := xml.Unmarshal([]byte(src), &s); err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", s)

    var s2 *Social2
    if err := xml.Unmarshal([]byte(src), &s2); err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", s2)
}

const src = `<social>
    <facebook>someface</facebook>
    <twitter>sometwitter</twitter>
    <linkedin>somelinkedin</linkedin>
</social>`

Output (try it on the Go Playground):

&{XMLName:{Space: Local:social} HasFacebook:{Facebook:someface} Twitter:sometwitter Youtube:}
&{HasFacebook:{Facebook:someface} Linkedin:somelinkedin}

Upvotes: 2

Volker
Volker

Reputation: 42486

Is it possible?

No. This is not possible.

Upvotes: 1

Related Questions