来自远程服务器的API响应(响应内容类型:text / html):
<status>success</status>
<statusmsg>online</statusmsg>
<vmstat>online</vmstat>
<hostname>kvm-vps2</hostname>
<ipaddress>123.456.789.99</ipaddress>
我尝试解析上面对Go结构的API响应。我下面的方法都不起作用:
方法#1代码
type result struct {
Status string `xml:",chardata"`
Statusmsg string `xml:",chardata"`
Vmstat string `xml:",chardata"`
Hostname string `xml:",chardata"`
Ipaddress string `xml:",chardata"`
}
方法#2代码
type result struct {
Status string `xml:"status"`
Statusmsg string `xml:"statusmsg"`
Vmstat string `xml:"vmstat"`
Hostname string `xml:"hostname"`
Ipaddress string `xml:"ipaddress"`
}
[从方法1开始,我仅设法获得了Status
值。其他值为空。对于方法2,所有值均为空。
解组码:
// other code
r := result{}
err = xml.Unmarshal(body, &r)
// other code
这里应该解决什么问题,以便我可以访问所有API响应值?
该响应不是有效的XML文档,因此您不能将其解码为文档。
但是,它可以看作XML文档的系列,因此您可以使用xml.Decoder
对其进行一次解码。
以下解决方案使用xml.Decoder
作为响应正文:body
。
例如:
Response.Body
此输出(在Response.Body
上尝试):
var res result
dec := xml.NewDecoder(body)
var err error
decField := func(v interface{}) {
if err == nil {
err = dec.Decode(v)
}
}
decField(&res.Status)
decField(&res.Statusmsg)
decField(&res.Vmstat)
decField(&res.Hostname)
decField(&res.Ipaddress)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%+v\n", res)
是,不方便逐场解码。
另一个选择是用标签将其包装以使其成为有效的XML文档:
Go Playground
此输出相同。在{Status:success Statusmsg:online Vmstat:online Hostname:kvm-vps2 Ipaddress:123.456.789.99}
上尝试。
是,上述解决方案必须首先在内存中读取主体。
尽管我们可以避免读取身体并将其保留在内存中。我们可以构造一个读取器,当读取它时,它首先提供开始包装标签,然后提供“原始”正文,最后提供结束标签。为此,我们可以使用buf := &bytes.Buffer{}
buf.WriteString("<root>")
if _, err := io.Copy(buf, body); err != nil {
panic(err)
}
buf.WriteString("</root>")
var res result
if err := xml.Unmarshal(buf.Bytes(), &res); err != nil {
panic(err)
}
fmt.Printf("%+v\n", res)
:
Go Playground
这再次输出相同。在io.MultiReader()
上尝试这个。