解组嵌套 xml golang

Unmarshaling nested xml golang

我想将嵌套的 xml 解组为 golang 结构。我要解组的 xml 如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<status>
    <authorized>true</authorized>
    <plan>Basic</plan>
    <usage_reports>
        <usage_report metric="hits" period="day">
            <period_start>2021-07-20 00:00:00 +0000</period_start>
            <period_end>2021-07-21 00:00:00 +0000</period_end>
            <max_value>1000000</max_value>
            <current_value>0</current_value>
        </usage_report>
        <usage_report metric="hits.82343" period="day">
            <period_start>2021-07-20 00:00:00 +0000</period_start>
            <period_end>2021-07-21 00:00:00 +0000</period_end>
            <max_value>1000000</max_value>
            <current_value>0</current_value>
        </usage_report>
    </usage_reports>
</status>

为了解组,我定义了两个 go 结构,如下所示。

// UsageReport represents the usage report of a particular metric.
type UsageReport struct {
    Usage   string `xml:"usage_report,chardata"`
    Metric  string `xml:"metric,attr"`
    Period  string `xml:"period,attr"`
    Start   string `xml:"period_start"`
    End     string `xml:"period_end"`
    Max     int64  `xml:"max_value"`
    Current int64  `xml:"current_value"`
}

// AuthResponse represents the structure of the response from authorize calls.
type AuthResponse struct {
    Status     xml.Name      `xml:"status"`
    Authorized bool          `xml:"authorized"`
    Plan       string        `xml:"plan"`
    Usages     []UsageReport `xml:"usage_reports"`
}

但是当我尝试使用 xml.Unmarshal 解组时,只有 PlanAuthorized 值被解组。解组结果如下图

XML: {{ } true Basic []}

试试这个 go playground. I use this tool 作弊并帮助我从 XML 数据生成 Go 类型。

package main

import (
    "encoding/xml"
    "fmt"
)

type Status struct {
    XMLName      xml.Name `xml:"status"`
    Text         string   `xml:",chardata"`
    Authorized   string   `xml:"authorized"`
    Plan         string   `xml:"plan"`
    UsageReports struct {
        Text        string `xml:",chardata"`
        UsageReport []struct {
            Text         string `xml:",chardata"`
            Metric       string `xml:"metric,attr"`
            Period       string `xml:"period,attr"`
            PeriodStart  string `xml:"period_start"`
            PeriodEnd    string `xml:"period_end"`
            MaxValue     string `xml:"max_value"`
            CurrentValue string `xml:"current_value"`
        } `xml:"usage_report"`
    } `xml:"usage_reports"`
}

func main() {
    status := Status{}
    err := xml.Unmarshal([]byte(xmlStr), &status)
    if err != nil {
        panic(err)
    }
    fmt.Println(status.UsageReports.UsageReport[0].MaxValue)
}

const xmlStr = `<?xml version="1.0" encoding="UTF-8"?><status><authorized>true</authorized><plan>Basic</plan><usage_reports><usage_report metric="hits" period="day"><period_start>2021-07-20 00:00:00 +0000</period_start><period_end>2021-07-21 00:00:00 +0000</period_end><max_value>1000000</max_value><current_value>0</current_value></usage_report><usage_report metric="hits.82343" period="day"><period_start>2021-07-20 00:00:00 +0000</period_start><period_end>2021-07-21 00:00:00 +0000</period_end><max_value>1000000</max_value><current_value>0</current_value></usage_report></usage_reports></status>`

为了获得 Usages 字段的值,请根据 mkopriva 的建议将 xml:"usage_reports" 修改为 xml:"usage_reports>usage_report"

package main

import (
    "encoding/xml"
    "fmt"
)

type UsageReport struct {
    Metric  string `xml:"metric,attr"`
    Period  string `xml:"period,attr"`
    Start   string `xml:"period_start"`
    End     string `xml:"period_end"`
    Max     int64  `xml:"max_value"`
    Current int64  `xml:"current_value"`
}

type AuthResponse struct {
    Status     xml.Name      `xml:"status"`
    Authorized bool          `xml:"authorized"`
    Plan       string        `xml:"plan"`
    Usages     []UsageReport `xml:"usage_reports>usage_report"`
}

var data = []byte(`<?xml version="1.0" encoding="UTF-8"?>
<status>
    <authorized>true</authorized>
    <plan>Basic</plan>
    <usage_reports>
        <usage_report metric="hits" period="day">
            <period_start>2021-07-20 00:00:00 +0000</period_start>
            <period_end>2021-07-21 00:00:00 +0000</period_end>
            <max_value>1000000</max_value>
            <current_value>0</current_value>
        </usage_report>
        <usage_report metric="hits.82343" period="day">
            <period_start>2021-07-20 00:00:00 +0000</period_start>
            <period_end>2021-07-21 00:00:00 +0000</period_end>
            <max_value>1000000</max_value>
            <current_value>0</current_value>
        </usage_report>
    </usage_reports>
</status>
`)

func main() {
    r := AuthResponse{}
    if err := xml.Unmarshal(data, &r); err != nil {
        panic(err)
    }
    fmt.Println(r)
}

输出:

{{ } true Basic [{hits day 2021-07-20 00:00:00 +0000 2021-07-21 00:00:00 +0000 1000000 0} {hits.82343 day 2021-07-20 00:00:00 +0000 2021-07-21 00:00:00 +0000 1000000 0}]}