英文:
Interfaces and encoding/xml Unmarshal
问题
我正在写一个与SOAP服务交互的SOAP服务。SOAP API 的一部分是返回查询结果的,我希望提供用于解码信封的基本结构体,同时允许开发人员填写编码/解码为 XML 的接口。
type QueryEnvelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body *QueryBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type QueryBody struct {
QueryResult *QueryResult `xml:"queryResponse>result"`
}
type QueryResult struct {
Done bool `xml:"done"`
Size int `xml:"size"`
Records Record `xml:"records"`
}
type Record interface {
UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
}
是否可以像这样注入一个用于解码的接口,还是必须在 QueryEnvelope{}
级别接受接口?
理想情况下,客户端代码应该如下所示:
type Record struct {
Id int `xml:"id"`
Name string `xml:"name"`
}
func (r *Record) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// 在这里进行解码,或者最好的情况下,我甚至不需要实现 UnmarshalXML()!
}
res, err := Query("select id from table", Record{})
这意味着他们不需要重现 QueryEnvelope
结构体(作为使用我创建的包的开发人员)。
英文:
I have a soap service I'm writing against. One portion of the soap API is for returning a query result, and I'm hoping to provide the base structs for decoding the envelope, while allow a developer to fill in the interface in which encoding/xml will decode to.
type QueryEnvelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body *QueryBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type QueryBody struct {
QueryResult *QueryResult `xml:"queryResponse>result"`
}
type QueryResult struct {
Done bool `xml:"done"`
Size int `xml:"size"`
Records Record `xml:"records"`
}
type Record interface {
UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
}
Is it possible to inject an interface like this for unmarhsalling or do I have to accept the interface at the QueryEnvelope{} level?
Ideally client side would act as such:
type Record struct {
Id int `xml:"id"`,
Name stirng `xml:"name"`
}
func (r *Record) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// unmasrshal here, or best case I dont even need to implment UnmarsahlXML()!
}
res, err := Query("select id from table", Record{})
This would mean that they don't have to reproduce the QueryEnvelope struct (as a developer using the package I'm creating)
答案1
得分: 1
常见的解决方案是要求客户端传递一个指向他的结构体实例的指针,如下所示:
// 客户端的自定义结构体
type ClientStruct struct {
Id int `xml:"id"`
Name string `xml:"name"`
}
// 这将是你的 API
func Query(foo string, v interface{}) {
fakeXmlResult := "<test><id>012345</id><name>MyName</name></test>"
xml.Unmarshal([]byte(fakeXmlResult), v)
}
func main() {
r := ClientStruct{}
Query("SQL QUERY", &r) // 注意这里的 &
fmt.Println(r)
}
我正确理解了你的问题吗?
英文:
The common solution is to ask the client to pass a pointer to his struct instance like so:
// The custom struct of your client
type ClientStruct struct {
Id int `xml:"id"`
Name string `xml:"name"`
}
// This would be your API
func Query(foo string, v interface{}) {
fakeXmlResult := "<test><id>012345</id><name>MyName</name></test>"
xml.Unmarshal([]byte(fakeXmlResult), v)
}
func main() {
r := ClientStruct{}
Query("SQL QUERY", &r) // Note the &
fmt.Println(r)
}
Did I understand your question correctly?
答案2
得分: 0
所以你确实可以在中间插入一个接口,我在为解码器分配内存时失败了:
包:
type QueryEnvelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body *QueryBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type QueryBody struct {
QueryResult *QueryResult `xml:"queryResponse>result"`
}
type QueryResult struct {
Done bool `xml:"done"`
Size int `xml:"size"`
Records interface{} `xml:"records"`
}
func (r *Resource) Query(sql string, r interface{}) error {
t := &QueryEnvelope{Body: &QueryBody{QueryResult: &QueryResult{Records: r}}}
//执行查询并将结果解组到t中
return err
}
客户端/主要代码:
type Record struct {
Id string `xml:"id"`
Name string `xml:"name"`
}
r := new([]*Record) // 必须使用new分配内存
err = ent.Query("select id, name from account limit 3", r)
英文:
So you can indeed inject an interface partway through, I was failing it allocate memory for the decoder to work:
Package:
type QueryEnvelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body *QueryBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type QueryBody struct {
QueryResult *QueryResult `xml:"queryResponse>result"`
}
type QueryResult struct {
Done bool `xml:"done"`
Size int `xml:"size"`
Records interface{} `xml:"records"`
}
func (r *Resource) Query(sql string, r interface{}) error {
t := &QueryEnvelope{Body: &QueryBody{QueryResult: &QueryResult{Records: r}}}
//do query and unmarshal into t
return err
}
Client / main:
type Record struct {
Id string `xml:"id"`
Name string `xml:"name"`
}
r := new([]*Record) // must allocate memory using new
err = ent.Query("select id, name from account limit 3", r)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论