【问题标题】:Parse XML to struct containing slice将 XML 解析为包含切片的结构
【发布时间】:2018-09-05 20:31:06
【问题描述】:

情况:

我有这个 XML 结构:

<group id="26659127">
    <member ref="292403538"/>
    <member ref="298884289"/>
    <member ref="261728686"/>
    <info k="name" v="omega"/>
    <info k="rank" v="16"/>
</group>

我需要把这个 XML 转换成这个结构:

{
    Id: "26659127",
    Members: ["26659127", "298884289", "261728686"],
    Info: [
        {
            Key: "name",
            Value: "omega"
        },
        {
            Key: "rank",
            Value: "16"
        }
    ]
}

问题:

我已经创建了一个用于解析 XML 的结构:

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"`
}

但是,如您所见,我还没有为Members 定义表达式。其实我试过把xml:"member,ref,attr"xml:"member:ref,attr"放在这里,但是没用。

问题:

有没有可能解决这个问题?如果是,我应该使用什么表达方式?

【问题讨论】:

  • 按照与info 相同的方式执行此操作:接收member 元素的对象数组,这些对象具有接收ref 属性的字段。
  • @Adrian 是的,我知道。问题是我的数据库结构要求我将其保留为字符串数组,而不是对象数组。我知道我可以遍历一个对象数组并形成一个字符串数组,但在我的情况下这不是最好的选择(我有大约 6,000,000,000 个 xml 文档,所以我需要有很好的速度)
  • 就性能而言,与首先将 XML 解析为结构体相比,迭代字符串切片的效果可以忽略不计。

标签: xml parsing go struct slice


【解决方案1】:

不幸的是,没有办法通过仅使用结构字段标签来使用默认 XML 解组器来实现您的目标,因此您必须:

  1. 为具有“ref”字段的“Members”字段提取结构类型(类似于“Info”类型)。
  2. 为“Member”使用自定义类型,它是一个字符串,通过从关联的 XML 元素中提取“ref”属性的值来实现 xml.Unmarshaler

以下是如何实施上述策略 2 的示例 (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:...

请注意,您甚至可以将此结构直接编组为您列出的示例 JSON 格式:

bs, err := json.MarshalIndent(group, "", "  ")
if err != nil {
    panic(err)
}
fmt.Println(string(bs))
// {
//   "Id": "26659127",
//   "Members": [
//     "292403538",
//     "298884289",
//     "261728686"
//   ],
//   "Info": [
//     ...

【讨论】:

    猜你喜欢
    • 2015-05-11
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 2019-02-17
    • 2019-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多