Reputation: 788
I am dealing with an API that is expecting XML that is generally formatted like so.
<receiver>
<receiver_type>test</receiver_type>
<hostnames>http://posttestserver.com</hostnames>
<credentials>
<credential>
<name>app-id</name>
<value>1234</value>
<safe>true</safe>
</credential>
<credential>
<name>app-secret</name>
<value>5678</value>
</credential>
</credentials>
</receiver>
Therefore, in my Go code, I made these structs to use in my functions and marshal into the XML structure. Note that different receivers can have different sets of credentials.
type Receiver1 struct {
XMLName xml.Name `xml:"receiver"`
ReceiverType string `xml:"receiver_type"`
HostNames string `xml:"hostnames"`
Credentials Receiver1Credentials `xml:"credentials"`
}
type Receiver2 struct {
XMLName xml.Name `xml:"receiver"`
ReceiverType string `xml:"receiver_type"`
HostNames string `xml:"hostnames"`
Credentials Receiver2Credentials `xml:"credentials"`
}
type Receiver1Credentials struct {
AppID Credential `xml:"credential"`
AppSecret Credential `xml:"credential"`
}
type Receiver2Credentials struct {
UserName Credential `xml:"credential"`
Password Credential `xml:"credential"`
AppID Credential `xml:"credential"`
}
type Credential struct {
Name string `xml:"name"`
Value string `xml:"value"`
Safe bool `xml:"safe"`
}
However this produces runtime errors along the lines of Receiver1Credentials field "AppID" with tag "credential" conflicts with field "AppSecret" with tag "credential"
meaning that I can't directly tag the Credentials fields the same thing. I've tried using a field XMLName xml.Name xml:"credential"
(like on the Receiver structs) on the Credential struct, but it gets overwritten by the tag on the Credentials structs. Does anyone know how I could work around this?
Upvotes: 4
Views: 826
Reputation: 9116
To Marshal the data into xml, you can simply create a simple receiver struct, initialize it, and call xml.Marshal(...)
.
(Note that to nest credential
into credentials
, explicit xml tag needs to be associated with the fields)
type Receiver struct {
XMLName xml.Name `xml:"receiver"`
ReceiverType string `xml:"receiver_type"`
HostNames string `xml:"hostnames"`
Credentials []Credential `xml:"credentials>credential"` // necessary to allow tag nesting
}
type Credential struct {
Name string `xml:"name"`
Value string `xml:"value"`
Safe bool `xml:"safe,omitempty"` // omitempty does not include the tag if if it's empty
}
Now you can simply initialize a Receiver
and marshal it into xml:
r := &Receiver{
ReceiverType: "test",
HostNames: "http://posttestserver.com",
Credentials: []Credential{
Credential{"app-id", "1234", true},
Credential{"app-secret", "5678", false},
},
}
a, _ := xml.MarshalIndent(r, "", " ") // a is []byte containing xml encoded data
(working example: https://play.golang.org/p/JZcUUK9P1f)
Original answer - method to unmarshal the above xml into receiver
If you can avoid parsing the xml data directly into Receiver[12]Credentials
, you can unmarshal the xml data into a much simpler structure (Receiver
and Credential
above) using the following method:
receiver := &Receiver{}
xml.Unmarshal(xmlDataByteSlice, receiver)
This would store all the Credential
objects in receiver.Credentials
above:
fmt.Println(receiver.Credentials)
// [{app-id 1234 true} {app-secret 5678 false}]
You can then perhaps use a switch case
on receiver,Credential.Name
to initialize Receiver[12]Credentials
accordingly.
Working example: https://play.golang.org/p/jq3BrxKVo-
Upvotes: 4