英文:
Go: XML Unmarshal Nested Structs into interface{}
问题
我来自Python背景,这是我第一次正式涉足Go,所以我觉得还没有完全理解。
我目前正在使用Go实现Affiliate Window XML API。该API遵循请求和响应的标准结构,因此我试图保持代码的DRY原则。信封的结构始终相同,类似于这样:
<Envelope>
<Header></Header>
<Body></Body>
</Envelope>
Header
和Body
的内容根据请求和响应的不同而不同,因此我创建了一个基本的Envelope
结构体:
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"`
}
这对于将请求的XML进行编组很有效,但是在解组时我遇到了问题:
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) // 为什么我无法访问这个?
}
这个链接http://play.golang.org/p/v-MkfEyFPM 可能更好地描述了问题,比我用文字描述要好:p
谢谢,
Chris
英文:
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:
<!-- language: lang-xml -->
<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
<!-- language: lang-golang -->
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:
<!-- language: lang-golang -->
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
答案1
得分: 2
Envelope
结构体内的 Header
字段的类型是 interface{}
,不是一个 struct
,因此你不能引用它的任何字段。
为了引用名为 Quota
的字段,你需要声明一个包含 Quota
字段的静态类型的 Header
,类似于以下代码:
type HeaderStruct struct {
Quota string
}
type Envelope struct {
// 其他字段省略
Header HeaderStruct
}
如果你不知道它的具体类型,或者无法确定一个单一的类型,你可以将其保留为 interface{}
,但是你需要在运行时使用 类型断言 或 类型切换 将其转换为静态类型,后者的代码示例如下:
headerStruct, ok := responseEnvelope.Header.(HeaderStruct)
// 如果 ok 为 true,则 headerStruct 的类型是 HeaderStruct
// 否则 responseEnvelope.Header 的类型不是 HeaderStruct
另一种选择是使用反射来访问 Envelope.Header
值的命名字段,但如果可能的话,请尝试使用其他方法解决。如果你对在 Go 中使用反射感兴趣,我建议先阅读 The Laws of Reflection 博文。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论