xml - Parse XML to struct containing slice
问题描述
Situation:
I have this XML structure:
<group id="26659127">
<member ref="292403538"/>
<member ref="298884289"/>
<member ref="261728686"/>
<info k="name" v="omega"/>
<info k="rank" v="16"/>
</group>
I need to convert this XML into this struct:
{
Id: "26659127",
Members: ["26659127", "298884289", "261728686"],
Info: [
{
Key: "name",
Value: "omega"
},
{
Key: "rank",
Value: "16"
}
]
}
Problem:
I created a struct for parsing XML already:
type Group struct {
Id string `xml:"id,attr"`
Members []string `xml:" "`
Info []Info `xml:"info"`
}
type Info struct {
Key string `xml:"k,attr"`
Value string `xml:"v,attr"`
}
But, as you can see I haven't defined an expression for Members
yet. Actually, I tried putting xml:"member,ref,attr"
and xml:"member:ref,attr"
in here, but it didn't work.
Question:
Is there a possibility to solve this issue? If yes, what expression I should use?
解决方案
Unfortunately there is no way to use the default XML unmarshaler to achieve your goal by using only struct field tags so you'll have to either:
- Extract a struct type for the "Members" field which has a "ref" field (similar to the "Info" type).
- Use a custom type for "Member" which is a string and implements
xml.Unmarshaler
by extracting the value of the "ref" attribute from the associated XML element.
Here is an example of how you can implement strategy #2 above (Go Playground):
type Group struct {
Id string `xml:"id,attr"`
Members []MemberRef `xml:"member"`
Info []Info `xml:"info"`
}
type MemberRef string
func (m *MemberRef) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*m = MemberRef(start.Attr[0].Value) // Assume only the "ref" attribute exists.
_, err := d.Token() // Consume and discard the synthetic xml.EndElement.
return err
}
// ...
var group Group
err := xml.Unmarshal([]byte(xmlstr), &group)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", group)
// main.Group{Id:"26659127", Members:[]main.MemberRef{"292403538", "298884289", "261728686"}, Info:...
Note that you can even marshal this struct directly into the example JSON format you listed:
bs, err := json.MarshalIndent(group, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(bs))
// {
// "Id": "26659127",
// "Members": [
// "292403538",
// "298884289",
// "261728686"
// ],
// "Info": [
// ...
推荐阅读
- docker - Docker - 挂载没有子文件夹的 cifs 卷
- python - 欧拉计划解决方案不起作用:低于 200 万的所有素数之和
- sql - 如何仅选择日期范围内包含列值为 0 的 id?
- java - NetBeans Java GUI 项目 - 缺少设计选项卡
- openam - OpenAM 安装无法创建默认配置,OpenDS 中出现错误
- symfony - 在 Symfony 5 迁移类中访问实体管理器?
- python - numba.cuda 实例化对象
- node.js - React Native 视图不是 100% 宽度
- angular - Ionic Android 默认 build.gradle 设置
- javascript - 使用 VueJS 在 div 中随机定位图标