如何将不带根/父元素的XML转换为结构?

问题描述 投票:1回答:1

来自远程服务器的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 go unmarshalling
1个回答
0
投票

该响应不是有效的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()上尝试这个。

© www.soinside.com 2019 - 2024. All rights reserved.