为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
回首忆惘然 2023-08-07 19:00:18
来自远程服务器的 API 响应(响应内容类型:text/html):<status>success</status><statusmsg>online</statusmsg><vmstat>online</vmstat><hostname>kvm-vps2</hostname><ipaddress>123.456.789.99</ipaddress>我尝试将上面的 API 响应解析为 Go 结构。我的以下方法均无效:方法#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 coder := result{}err = xml.Unmarshal(body, &r)// other code这里应该修复什么以便我可以访问所有 API 响应值?
查看完整描述

1 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

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



查看完整回答
反对 回复 2023-08-07
  • 1 回答
  • 0 关注
  • 105 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信