如何将没有根/父元素的XML转换为struct?

祖尔米·扎努丁(Zulhilmi Zainudin):

来自远程服务器的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响应值?

icza:

该响应不是有效的XML文档,因此您不能一步一步按原样对其进行解码,也不能在没有修改/“修饰”的情况下对其进行解码。

以下解决方案body用作未读响应正文流:Response.Body

1.解码为一系列XML文档

但是,可以将其视为一系列 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}

是的,不方便逐场解码。

2.阅读正文并用根标签包裹

另一个选择是用标签将其包装以使其成为有效的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上尝试一下

是的,以上解决方案必须先将主体读取到内存中。

3.包装体流而不将其读入内存

但是,我们可以避免必须阅读并将身体保留在内存中。我们可以构造一个阅读器,在阅读时首先提供开始包装标签,然后提供“原始”正文,最后提供结束标签。为此,我们可以使用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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章