go - Go中具有动态类型(空接口)的XML Unmarshal
问题描述
我需要解析具有动态元素的 XML 消息,因此我interface{}
在 Message 结构中使用了类型元素来表示它。
一旦我知道了这个动态元素的类型(在运行时),我就会初始化一个消息结构,然后尝试解组 XML 消息。但是,动态元素的内容并未解组。
这是一个我想要实现的 Go Playground,带有评论和实际与预期的输出: https: //play.golang.org/p/eKVetUPmVI2
我尝试了几种变体,但无法让解组按预期工作。谁能帮我理解为什么这种行为以及如何使它起作用?提前致谢。
代码(以防 Go Playground 链接有一天中断):
package main
import "fmt"
import "encoding/xml"
// XML root
type Message struct {
XMLName xml.Name `xml:"message"`
Operation Operation `xml:"operation"`
}
// An Operation can contain either a Create or an Update element
type Operation struct {
Create *Create `xml:"create"`
Update *Update `xml:"update"`
}
// Doesn't matter...
type Create struct{}
// Update contains a Color element or Any other element (we only know its type during runtime)
type Update struct {
Color *Color `xml:"color"`
Other Any
}
// Doesn't matter...
type Color struct{}
type Any interface{}
var xmlStr = []byte(`<message>
<operation>
<update>
<size>
<width>1000</width>
</size>
</update>
</operation>
</message>`)
func main() {
// At this point we already know what to expect to receive in Other, so we can declare a struct for its content (Size)
type Size struct {
XMLName xml.Name `xml:"size"`
Width string `xml:"width"`
}
// Unmarshal
msg := &Message{
Operation: Operation{
Update: &Update{
Other: &Size{}, // Here I'm setting Other to Size, so I would expect Go to unmarshal the <size> contents into it
},
},
}
if err := xml.Unmarshal(xmlStr, msg); err != nil {
fmt.Println(err)
}
// Marshal again
b, err := xml.MarshalIndent(msg, "", " ")
if err != nil {
fmt.Println(err)
}
fmt.Printf("expected:\n\n%s\n\n", xmlStr)
fmt.Printf("actual:\n\n%s", string(b))
}
解决方案
根据encoding/xml
包文档:
如果 XML 元素包含与上述任何规则都不匹配的子元素,并且结构具有带有 tag 的字段
",any"
,则 unmarshal 会将子元素映射到该结构字段。
对您的代码进行一个小的更新,使其按您预期的方式工作:
将xml:",any"
标签添加到您的Other
字段定义中。
为了清理代码,我也会删除Any
类型,你不需要它。您可以将Other
字段定义更改为interface{}
使用标签键入xml:",any"
并完成相同的操作。
像这样:
Other interface{} `xml:",any"`
执行并查看捕获的“1000”。
我建议更新您的问题以直接包含您的代码,以使人们更容易找到/搜索/阅读您的问题。拥有 Go 游乐场链接也很有用,因此读者可以快速运行/调整/测试示例。
推荐阅读
- scala - 是否可以在 Scala 中的赋值/初始化之前声明一个 val?
- docker - Docker 容器中的 JetBrains/Teamtools “无法侦听地址 0.0.0.0 和端口 443”
- angular - 将 observable 转换为数组以绘制 googlechart
- swift - 左对齐的水平堆栈视图和顶部对齐的垂直堆栈视图
- tableau-api - 具有自定义字段的交互式仪表板
- php - 安装 SSL Codeigniter 后出错
- eclipse - eclipse Photon SQL 编辑器
- jupyter - 卡在运行模式 Jupyter Notebook
- r - 如何在列中查找单词
- php - 如何处理数据库请求输出中的序列中断