英文:
Unmarshal SOAP message with Go
问题
我相对于Go语言还比较新手。
我在尝试解析一个SOAP消息时遇到了问题。我的目标是抽象出Body元素的内容,并避免静态定义XML结构,因为它根据请求的操作而变化。
不幸的是,我找不到正确的方法来实现这一点。在这个例子中,GetContent函数应该接收一个包含内容的结构体的指针,并动态地将其添加到Body中以进行填充。但结果并不是预期的。
以下是示例代码:
package main
import (
"encoding/xml"
"fmt"
)
type Message interface{}
type EnvelopeResponse struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body Message `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type Body struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
Fault *Fault `xml:",omitempty"`
Content Message `xml:",omitempty"`
SOAPBodyContentType string `xml:"-"`
}
type Fault struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"`
Code string `xml:"faultcode,omitempty"`
String string `xml:"faultstring,omitempty"`
Actor string `xml:"faultactor,omitempty"`
Detail string `xml:"detail,omitempty"`
}
type GetHostNumberOfEntriesResponse struct {
XMLName xml.Name `xml:"urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse"`
NewHostNumberOfEntries int64 `xml:"NewHostNumberOfEntries"`
}
func GetContent(rawXml []byte, content interface{}) {
envelope := EnvelopeResponse{Body: Body{Content: content}}
xml.Unmarshal(rawXml, &envelope)
}
func main() {
b := []byte(`
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetHostNumberOfEntriesResponse xmlns:u="urn:dslforum-org:service:Hosts:1">
<NewHostNumberOfEntries>47</NewHostNumberOfEntries>
</u:GetHostNumberOfEntriesResponse>
</s:Body>
</s:Envelope>
`)
content := &GetHostNumberOfEntriesResponse{}
GetContent(b, content)
fmt.Println(*content)
}
你可以在这里的playground中查看示例代码:https://go.dev/play/p/BBR4vEXiPbc
英文:
I'm relatively new to the go language.
I have a problem trying to unmarshal a SOAP message. My attempt is to abstract the content of the Body element and avoid defining the XML structure statically, as it changes depending on the requested action.
Unfortunately I can't find a way to do this correctly. In the example, the GetContent function should receive a pointer to the struct that contains the content and add it dynamically to the Body, in order to be filled. But the result is not the expected one.
package main
import (
"encoding/xml"
"fmt"
)
type Message interface{}
type EnvelopeResponse struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body Message `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type Body struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
Fault *Fault `xml:",omitempty"`
Content Message `xml:",omitempty"`
SOAPBodyContentType string `xml:"-"`
}
type Fault struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"`
Code string `xml:"faultcode,omitempty"`
String string `xml:"faultstring,omitempty"`
Actor string `xml:"faultactor,omitempty"`
Detail string `xml:"detail,omitempty"`
}
type GetHostNumberOfEntriesResponse struct {
XMLName xml.Name `xml:"urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse"`
NewHostNumberOfEntries int64 `xml:"NewHostNumberOfEntries"`
}
func GetContent(rawXml []byte, content interface{}) {
envelope := EnvelopeResponse{Body: Body{Content: content}}
xml.Unmarshal(rawXml, &envelope)
}
func main() {
b := []byte(`
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetHostNumberOfEntriesResponse xmlns:u="urn:dslforum-org:service:Hosts:1">
<NewHostNumberOfEntries>47</NewHostNumberOfEntries>
</u:GetHostNumberOfEntriesResponse>
</s:Body>
</s:Envelope>
`)
content := &GetHostNumberOfEntriesResponse{}
GetContent(b, content)
fmt.Println(*content)
}
Here the example in the playground:
答案1
得分: 0
你使用了一些interface{}
,为什么?以下是测试通过的代码:
package main
import (
"encoding/xml"
"fmt"
)
type Message interface{}
type EnvelopeResponse struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body Body
}
type Body struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
GetHostNumberOfEntriesResponse GetHostNumberOfEntriesResponse
Fault *Fault `xml:",omitempty"`
Content Message `xml:",omitempty"`
SOAPBodyContentType string `xml:"-"`
}
type Fault struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"`
Code string `xml:"faultcode,omitempty"`
String string `xml:"faultstring,omitempty"`
Actor string `xml:"faultactor,omitempty"`
Detail string `xml:"detail,omitempty"`
}
type GetHostNumberOfEntriesResponse struct {
XMLName xml.Name `xml:"urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse"`
NewHostNumberOfEntries int64 `xml:"NewHostNumberOfEntries"`
}
func GetContent(rawXml []byte) *EnvelopeResponse {
envelope := EnvelopeResponse{}
xml.Unmarshal(rawXml, &envelope)
return &envelope
}
func main() {
b := []byte(`
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetHostNumberOfEntriesResponse xmlns:u="urn:dslforum-org:service:Hosts:1">
<NewHostNumberOfEntries>47</NewHostNumberOfEntries>
</u:GetHostNumberOfEntriesResponse>
</s:Body>
</s:Envelope>
`)
envelope := GetContent(b)
fmt.Println(envelope)
}
&{{http://schemas.xmlsoap.org/soap/envelope/ Envelope} {{http://schemas.xmlsoap.org/soap/envelope/ Body} {{urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse} 47} <nil> <nil>
}}
英文:
you use some interface{}, Why? Follow is test pass code:
https://go.dev/play/p/OPkNScHjri1
package main
import (
"encoding/xml"
"fmt"
)
type Message interface{}
type EnvelopeResponse struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body Body
}
type Body struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
GetHostNumberOfEntriesResponse GetHostNumberOfEntriesResponse
Fault *Fault `xml:",omitempty"`
Content Message `xml:",omitempty"`
SOAPBodyContentType string `xml:"-"`
}
type Fault struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"`
Code string `xml:"faultcode,omitempty"`
String string `xml:"faultstring,omitempty"`
Actor string `xml:"faultactor,omitempty"`
Detail string `xml:"detail,omitempty"`
}
type GetHostNumberOfEntriesResponse struct {
XMLName xml.Name `xml:"urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse"`
NewHostNumberOfEntries int64 `xml:"NewHostNumberOfEntries"`
}
func GetContent(rawXml []byte) *EnvelopeResponse {
envelope := EnvelopeResponse{}
xml.Unmarshal(rawXml, &envelope)
return &envelope
}
func main() {
b := []byte(`
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetHostNumberOfEntriesResponse xmlns:u="urn:dslforum-org:service:Hosts:1">
<NewHostNumberOfEntries>47</NewHostNumberOfEntries>
</u:GetHostNumberOfEntriesResponse>
</s:Body>
</s:Envelope>
`)
envelope := GetContent(b)
fmt.Println(envelope)
}
&{{http://schemas.xmlsoap.org/soap/envelope/ Envelope} {{http://schemas.xmlsoap.org/soap/envel
ope/ Body} {{urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse} 47} <nil> <nil>
}}
答案2
得分: 0
我找到的解决方案是使用泛型来表示主体的变量和参数化内容。
以下是我期望的代码:
package main
import (
"encoding/xml"
"fmt"
)
type EnvelopeResponse[T any] struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body Body[T] `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type Body[T any] struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
Fault *Fault `xml:",omitempty"`
Content T `xml:",omitempty"`
SOAPBodyContentType string `xml:"-"`
}
type Fault struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"`
Code string `xml:"faultcode,omitempty"`
String string `xml:"faultstring,omitempty"`
Actor string `xml:"faultactor,omitempty"`
Detail string `xml:"detail,omitempty"`
}
type GetHostNumberOfEntriesResponse struct {
XMLName xml.Name `xml:"urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse"`
NewHostNumberOfEntries int64 `xml:"NewHostNumberOfEntries"`
}
func GetContent[T any](rawXml []byte, content T) {
envelope := EnvelopeResponse[T]{Body: Body[T]{Content: content}}
xml.Unmarshal(rawXml, &envelope)
}
func main() {
b := []byte(`
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetHostNumberOfEntriesResponse xmlns:u="urn:dslforum-org:service:Hosts:1">
<NewHostNumberOfEntries>47</NewHostNumberOfEntries>
</u:GetHostNumberOfEntriesResponse>
</s:Body>
</s:Envelope>
`)
content := &GetHostNumberOfEntriesResponse{}
GetContent(b, content)
fmt.Println(*content)
}
希望对你有帮助!
英文:
The solution I found is to use generics to represent the variable and parameterized content of the body.
This code works as I expect:
package main
import (
"encoding/xml"
"fmt"
)
type EnvelopeResponse[T any] struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body Body[T] `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type Body[T any] struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
Fault *Fault `xml:",omitempty"`
Content T `xml:",omitempty"`
SOAPBodyContentType string `xml:"-"`
}
type Fault struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"`
Code string `xml:"faultcode,omitempty"`
String string `xml:"faultstring,omitempty"`
Actor string `xml:"faultactor,omitempty"`
Detail string `xml:"detail,omitempty"`
}
type GetHostNumberOfEntriesResponse struct {
XMLName xml.Name `xml:"urn:dslforum-org:service:Hosts:1 GetHostNumberOfEntriesResponse"`
NewHostNumberOfEntries int64 `xml:"NewHostNumberOfEntries"`
}
func GetContent[T any](rawXml []byte, content T) {
envelope := EnvelopeResponse[T]{Body: Body[T]{Content: content}}
xml.Unmarshal(rawXml, &envelope)
}
func main() {
b := []byte(`
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetHostNumberOfEntriesResponse xmlns:u="urn:dslforum-org:service:Hosts:1">
<NewHostNumberOfEntries>47</NewHostNumberOfEntries>
</u:GetHostNumberOfEntriesResponse>
</s:Body>
</s:Envelope>
`)
content := &GetHostNumberOfEntriesResponse{}
GetContent(b, content)
fmt.Println(*content)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论