【问题标题】:XML Unmarshal with dynamic type (empty interface) in GoGo中具有动态类型(空接口)的XML Unmarshal
【发布时间】:2019-12-02 19:07:55
【问题描述】:

我需要解析具有动态元素的 XML 消息,因此我使用了 interface{} 类型的元素在我的 Message 结构中表示它。

一旦我知道了这个动态元素的类型(在运行时),我就会初始化一个消息结构,然后尝试解组 XML 消息。但是,动态元素的内容并未解组。

这是一个 Go Playground,其中包含我想要实现的目标,包括 cmets 以及实际与预期的输出: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))
}

【问题讨论】:

    标签: go


    【解决方案1】:

    根据encoding/xml 包文档:

    如果 XML 元素包含一个不匹配的子元素 以上规则和结构有一个带有标签",any"的字段, unmarshal 将子元素映射到该结构字段。

    对您的代码进行一个小更新,使其按预期工作:

    xml:",any" 标签添加到您的Other 字段定义中。

    为了清理代码,我还要删除Any 类型,你不需要它。您可以将Other 字段定义更改为使用标签xml:",any" 键入interface{} 并完成相同的操作。

    像这样:

    Other interface{} `xml:",any"`
    

    执行并查看捕获的“1000”。

    我建议更新您的问题以直接包含您的代码,以便人们更轻松地查找/搜索/阅读您的问题。拥有 Go 游乐场链接也很有用,因此读者可以快速运行/调整/测试示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 2021-01-25
      相关资源
      最近更新 更多