在go

时间:2017-12-13 11:25:44

标签: xml go soap unmarshalling

我正在尝试使用以下结构解组以下SOAP响应。

var data = `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3rg/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <doSendResponse>
            <doSendResult>Send OK.&lt;ReturnIDs&gt;c71cf425f5;e5e4dbb5ca&lt;/ReturnIDs&gt;</doSendResult>
        </doSendResponse>
    </soap:Body>
</soap:Envelope>`

type ResponseBody struct {
    ResponseBody SendResponse `xml:"Body"`
}
type SendResponse struct {
    Result Result `xml:"doSendResponse"`
}
type Result struct {
    RawMessage string `xml:"doSendResult"`
}

一切顺利,直到<doSendResult>元素之后 该特定标签包含一条消息,即“发送OK”。和一个HTML编码的<ReturnIDs>元素,问题不在于HTML编码部分,我已经看过this question and the accepted answer. 我的问题是我无法提取消息和返回ID。

我尝试使用前面提到的问题中建议的方法,但是我失败了,Here是我到目前为止所尝试的。

package main

import (
    "encoding/xml"
    "fmt"
)

var data = `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3rg/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <doSendResponse>
            <doSendResult>Send OK.&lt;ReturnIDs&gt;c71cf425f5;e5e4dbb5ca&lt;/ReturnIDs&gt;</doSendResult>
        </doSendResponse>
    </soap:Body>
</soap:Envelope>`

type ResponseBody struct {
    ResponseBody SendResponse `xml:"Body"`
}
type SendResponse struct {
    Result Result `xml:"doSendResponse"`
}
type Result struct {
    RawMessage string `xml:"doSendResult"`
}
type RawMessage struct {
    IDs     string `xml:"ReturnIDs"`
}

func main() {
    var response ResponseBody
    err := xml.Unmarshal([]byte(data), &response)
    if err != nil {
        panic(err.Error())
    }
    fmt.Printf("%+v\n", response)

    var rawMessage RawMessage
    err = xml.Unmarshal([]byte(response.ResponseBody.Result.RawMessage), &rawMessage)
    if err != nil {
        panic(err.Error())
    }
    fmt.Printf("%+v\n", rawMessage)

}

输出:
{ResponseBody:{Result:{RawMessage:Send OK.<ReturnIDs>c71cf425f5;e5e4dbb5ca</ReturnIDs>}}} {IDs:} 我也尝试过Unesacpe的回复,然后尝试解组,部分工作,但这种方法有3个主要问题:

  1. 太慢了
  2. 我只能get the ReturnIDsthe message,而不是两者。
  3. 我认为这只是一个丑陋的黑客,必须有更好的方法来做到这一点(我还没有意识到。)
  4. 那么,如何提取消息的值(发送确定。)和<ReturnIDs>

2 个答案:

答案 0 :(得分:0)

由于doSendResult元素的内容似乎是“自定义”格式(与HTML,XML等格式良好的文档相对),正则表达式可能是解析结果在这里。

例如:

type SendResult struct {
  Status    string
  ReturnIds []string
}

var doSendResultRegex = regexp.MustCompile("^Send (.*?)\\.<ReturnIDs>(.*?)</ReturnIDs>$")

func ParseSendResult(s string) *SendResult {
  ss := doSendResultRegex.FindStringSubmatch(s)
  if ss == nil {
    return nil
  }
  return &SendResult{
    Status:    ss[1],
    ReturnIds: strings.Split(ss[2], ";"),
  }
}

// ...
fmt.Println("%#v\n", ParseSendResult(response.Result.RawMessage))
// &main.SendResult{
//   Status:    "OK",
//   ReturnIds: []string{"c71cf425f5", "e5e4dbb5ca"}
// }

当然,您可能希望根据该数据的其他示例修改doSendResultRegex表达式,但上面的代码应该说明这个想法。

答案 1 :(得分:0)

您可以通过多种方式解码doSendResult标记内容,但我做了一个示例:

play.golang.org/p/NC9YrWqK0k

我定义了两个与soap信封体内标签对应的类型:

type (
    SendResponse struct {
        SendResult SendResult `xml:"Body>doSendResponse>doSendResult"`
    }

    SendResult struct {
        RawMessage string   `xml:"-"`
        Text       string   `xml:"-"`
        IDS        []string `xml:"-"`
    }
)

类型SendResult有一个自定义的unmarshal函数来读取原始消息并填充结构

func (sr *SendResult) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    var raw string
    d.DecodeElement(&raw, &start)

    var st struct {
        Contents  string `xml:",chardata"`
        ReturnIDs string `xml:"ReturnIDs"`
    }

    err := xml.Unmarshal([]byte("<xml>"+raw+"</xml>"), &st)
    if err != nil {
        panic(err.Error())
    }

    sr.RawMessage = raw
    sr.Text = st.Contents
    sr.IDS = strings.Split(st.ReturnIDs, ";")

    return nil
}

这是如何使用:

const data = `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3rg/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <doSendResponse>
            <doSendResult>Send OK.&lt;ReturnIDs&gt;c71cf425f5;e5e4dbb5ca&lt;/ReturnIDs&gt;</doSendResult>
        </doSendResponse>
    </soap:Body>
</soap:Envelope>`

func main() {
    var sendResponse SendResponse

    err := xml.Unmarshal([]byte(data), &sendResponse)
    if err != nil {
        panic(err.Error())
    }

    fmt.Printf("%+v\n", sendResponse)
}