来自远程服务器的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文档,因此您不能一步一步按原样对其进行解码,也不能在没有修改/“修饰”的情况下对其进行解码。
以下解决方案body
用作未读响应正文流:Response.Body
。
但是,可以将其视为一系列 XML文档,因此您可以xml.Decoder
用来对它们进行逐一解码。
例如:
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)
输出(在Go Playground上尝试):
{Status:success Statusmsg:online Vmstat:online Hostname:kvm-vps2 Ipaddress:123.456.789.99}
是的,不方便逐场解码。
另一个选择是用标签将其包装以使其成为有效的XML文档:
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()
:
r := io.MultiReader(
strings.NewReader("<root>"),
body,
strings.NewReader("</root>"),
)
var res result
if err := xml.NewDecoder(r).Decode(&res); err != nil {
panic(err)
}
fmt.Printf("%+v\n", res)
这再次输出相同。在Go Playground上尝试一下。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句