Reputation: 966
I come from a Python background and this is my first proper foray into Go so I don't think things are clicking quite yet.
I'm currently implementing the Affiliate Window XML API in Go. The API follows a standard structure for Requests and Responses so to that end I'm trying to keep things dry. Envelopes always have the same structure, something like this:
<Envelope>
<Header></Header>
<Body></Body>
</Envelope>
The contents Header
and Body
will be different depending on what I'm requesting and the response so I created a base Envelope
struct
type Envelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
NS1 string `xml:"xmlns:ns1,attr"`
XSD string `xml:"xmlns:xsd,attr"`
Header interface{} `xml:"http://schemas.xmlsoap.org/soap/envelope/ Header"`
Body interface{} `xml:"Body"`
}
This works well for marshaling the XML for a request but I'm having problems with unmarshaling:
func NewResponseEnvelope(body interface{}) *Envelope {
envelope := NewEnvelope()
envelope.Header = &ResponseHeader{}
envelope.Body = body
return envelope
}
func main() {
responseBody := &GetMerchantListResponseBody{}
responseEnvelope := NewResponseEnvelope(responseBody)
b := bytes.NewBufferString(response)
xml.NewDecoder(b).Decode(responseEnvelope)
fmt.Println(responseEnvelope.Header.Quota) // Why can't I access this?
}
This http://play.golang.org/p/v-MkfEyFPM probably describes the problem better in code than I can in words :p
Thanks,
Chris
Upvotes: 2
Views: 612
Reputation: 417777
The type of the Header
field inside the Envelope
struct is interface{}
which is not a struct
so you cannot refer to any of its fields.
In order to refer to a field named Quota
, you have to declare Header
with a static type which contains a Quota
field, something like this:
type HeaderStruct struct {
Quota string
}
type Envelope struct {
// other fields omitted
Header HeaderStruct
}
If you don't know what type it will be or you can't commit to a single type, you can leave it as interface{}
, but then you have to use either Type switches or Type assertion to convert it to a static type at runtime, the latter would look something like this:
headerStruct, ok := responseEnvelope.Header.(HeaderStruct)
// if ok is true, headerStruct is of type HeaderStruct
// else responseEnvelope.Header is not of type HeaderStruct
Another option would be to use reflection to access named fields of the Envelope.Header
value, but try to solve it in other ways if possible. If you're interested in learning more about reflection in Go, I recommend reading The Laws of Reflection blog post first.
Upvotes: 2