-1

I'm programming an xml response API in golang. Following the examples in the xml documentation it's pretty easy to create the xml giving them attributes and more.

The thing is that I need multiple tags under the same name and in different order.

<block>
    <tag1>A Value1</tag1>
    <tag2>B Value1</tag2>
    <tag1>A Value2</tag1>
</block>

By creating a structure like

type Tag1 struct {
    Value string `xml:",chardata"`
}
type Tag2 struct {
    Value string `xml:",chardata"`
}
type Block struct {
    XMLName   xml.Name `xml:"block"`
    Tags1     []Tag1   `xml:"tag1"`
    Tags2     []Tag2   `xml:"tag2"`
}

I achieved this xml:

<block>
    <tag1>A Value1</tag1>
    <tag1>A Value2</tag1>
    <tag2>B Value1</tag2>
</block>

That's due to the array type inside the block definition. What I want, is a way to define that array type as an interface to inherit the two Tag types. Like this

type Block struct {
    XMLName   xml.Name `xml:"block"`
    Tags      []Tags   `xml:"tags"`
}
type (Tags t) Tag1 struct{
    Value string `xml:",chardata"`
}
type (Tags t) Tag2 struct{
    Value string `xml:",chardata"`
}

This way I could define the order of appearance in xml by the order of appending like

a1 := Tag1{"A Value1"}
b1 := Tag2{"B Value1"}
a2 := Tag1{"A Value2"}

arr :=  []Tags{}
arr = append(arr,a1)
arr = append(arr,b1)
arr = append(arr,a2)

v.Tags = arr

I've made some reading and I'm trying to avoid to implement the marshaling function used inside the xml package. Any help is appreciated, thanks.

MarAvFe
  • 468
  • 4
  • 15
  • 3
    There is no inheritance in Go. You could make `Tags` a slice of an interface type (either `interface{}` or something more specific) and do it that way. Types do not specify the interface(s) they want to implement. – Adrian Jan 25 '18 at 22:10
  • 1
    https://play.golang.org/p/xTQWrYaA86m – Shahriar Jan 26 '18 at 04:58

1 Answers1

0

I solved it differently. I just wasn't looking for the right approach. This question described what I needed. By defining the XMLName xml.Name value in the Tag1 struct, I could define the name of the tag programmatically. And then just include the different Tags value with the old friend []interface{} type.

type Tag1 struct {
    XMLName xml.Name
    Value   string `xml:",chardata"`
}
type Block struct {
    XMLName xml.Name `xml:"block"`
    Tags    []interface{}
}
a1 := Tag1{XMLName: xml.Name{Local: "tag1"}, Value: "A Value1"}
a2 := Tag1{XMLName: xml.Name{Local: "tag1"}, Value: "A Value2"}
b1 := Tag2{XMLName: xml.Name{Local: "tag2"}, Value: "B Value1"}

v := &Block{}
v.Tags = []interface{}{a1, b1, a2}

Check this example out to give it a play.

MarAvFe
  • 468
  • 4
  • 15