在Go中实现JSON与SOAP转换确实需要中间的结构体转换。你的理解基本正确,但具体实现可以有多种方式。
基本转换流程
package main
import (
"encoding/json"
"encoding/xml"
"fmt"
)
// SOAP结构体定义
type SOAPEnvelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body SOAPBody `xml:"Body"`
}
type SOAPBody struct {
XMLName xml.Name `xml:"Body"`
Data interface{}
}
// 业务数据结构
type UserRequest struct {
XMLName xml.Name `xml:"UserRequest"`
ID int `xml:"id" json:"id"`
Name string `xml:"name" json:"name"`
Email string `xml:"email" json:"email"`
}
// JSON转SOAP
func JSONToSOAP(jsonData []byte) ([]byte, error) {
var user UserRequest
// 1. JSON解组到结构体
if err := json.Unmarshal(jsonData, &user); err != nil {
return nil, err
}
// 2. 构建SOAP信封
envelope := SOAPEnvelope{
Body: SOAPBody{
Data: user,
},
}
// 3. 生成SOAP XML
soapXML, err := xml.MarshalIndent(envelope, "", " ")
if err != nil {
return nil, err
}
// 添加XML头部
result := []byte(xml.Header + string(soapXML))
return result, nil
}
// SOAP转JSON
func SOAPToJSON(soapData []byte) ([]byte, error) {
var envelope SOAPEnvelope
envelope.Body.Data = &UserRequest{}
// 1. XML解组到SOAP结构体
if err := xml.Unmarshal(soapData, &envelope); err != nil {
return nil, err
}
// 2. 转换为JSON
jsonData, err := json.MarshalIndent(envelope.Body.Data, "", " ")
if err != nil {
return nil, err
}
return jsonData, nil
}
func main() {
// 示例JSON数据
jsonInput := `{"id": 123, "name": "张三", "email": "zhangsan@example.com"}`
// JSON转SOAP
soap, err := JSONToSOAP([]byte(jsonInput))
if err != nil {
panic(err)
}
fmt.Println("SOAP输出:")
fmt.Println(string(soap))
// SOAP转JSON
jsonOutput, err := SOAPToJSON(soap)
if err != nil {
panic(err)
}
fmt.Println("\nJSON输出:")
fmt.Println(string(jsonOutput))
}
推荐的SOAP库
对于生产环境,建议使用成熟的SOAP库:
package main
import (
"fmt"
"github.com/hooklift/gowsdl/soap"
)
// 生成客户端代码
// go:generate gowsdl -o service.go -p main https://example.com/service?wsdl
func main() {
client := soap.NewClient("https://example.com/service")
// 使用生成的客户端代码调用SOAP服务
// response, err := client.SomeOperation(&request)
}
package main
import (
"fmt"
"github.com/tiaguinho/gosoap"
)
func main() {
// 创建SOAP客户端
client, err := gosoap.SoapClient("http://example.com/soap")
if err != nil {
panic(err)
}
// 设置SOAP请求参数
params := gosoap.Params{
"id": 123,
"name": "张三",
"email": "zhangsan@example.com",
}
// 调用SOAP方法
response, err := client.Call("UserOperation", params)
if err != nil {
panic(err)
}
// 获取响应
result := response.Get("UserResponse")
fmt.Println(result)
}
3. 自定义WSDL转换器示例
package main
import (
"encoding/xml"
"strings"
)
type WSDLConverter struct {
Namespace string
Service string
}
func (w *WSDLConverter) GenerateSOAPRequest(method string, data interface{}) (string, error) {
// 构建SOAP请求模板
template := `<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="%s">
<soap:Body>
<ns:%s>
%s
</ns:%s>
</soap:Body>
</soap:Envelope>`
// 将数据转换为XML
xmlData, err := xml.Marshal(data)
if err != nil {
return "", err
}
// 移除XML头部
xmlStr := strings.TrimSpace(string(xmlData))
xmlStr = strings.Replace(xmlStr, `<?xml version="1.0" encoding="UTF-8"?>`, "", 1)
request := fmt.Sprintf(template, w.Namespace, method, xmlStr, method)
return request, nil
}
// 使用示例
func main() {
converter := &WSDLConverter{
Namespace: "http://example.com/ns",
Service: "UserService",
}
user := UserRequest{
ID: 123,
Name: "张三",
Email: "zhangsan@example.com",
}
soapRequest, err := converter.GenerateSOAPRequest("CreateUser", user)
if err != nil {
panic(err)
}
fmt.Println(soapRequest)
}
处理复杂SOAP特性
package main
import (
"encoding/xml"
"fmt"
)
// 处理SOAP头部
type SOAPHeader struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Header"`
Auth *AuthHeader
}
type AuthHeader struct {
XMLName xml.Name `xml:"auth"`
Username string `xml:"username"`
Password string `xml:"password"`
}
// 完整的SOAP请求
type FullSOAPEnvelope struct {
XMLName xml.Name `xml:"soap:Envelope"`
XMLNS string `xml:"xmlns:soap,attr"`
Header *SOAPHeader `xml:"soap:Header,omitempty"`
Body SOAPBody `xml:"soap:Body"`
}
// 生成带认证的SOAP请求
func CreateAuthenticatedSOAPRequest(bodyData interface{}) ([]byte, error) {
envelope := FullSOAPEnvelope{
XMLNS: "http://schemas.xmlsoap.org/soap/envelope/",
Header: &SOAPHeader{
Auth: &AuthHeader{
Username: "admin",
Password: "secret",
},
},
Body: SOAPBody{
Data: bodyData,
},
}
return xml.MarshalIndent(envelope, "", " ")
}
这些示例展示了在Go中处理JSON与SOAP转换的基本模式。对于生产环境,建议使用成熟的SOAP库,它们已经处理了SOAP协议的各种细节,如命名空间、SOAP错误处理、WS-Security等。