xml - 以 golang 保留顺序混合 XML 解码

标签 xml go slice xml-deserialization

我需要从 XML 中提取报价,但要考虑节点顺序:

<items>
  <offer/>
  <product>
    <offer/>
    <offer/>
  </product>
  <offer/>
  <offer/>
</items>

以下结构将解码这些值,但会分成两个不同的 slice ,这将导致原始顺序丢失:

type Offers struct {
    Offers   []offer `xml:"items>offer"`
    Products []offer `xml:"items>product>offer"`
}

有什么想法吗?

最佳答案

一种方法是覆盖UnmarshalXML 方法。假设我们的输入如下所示:

<doc>
    <head>My Title</head>
    <p>A first paragraph.</p>
    <p>A second one.</p>
</doc>

我们要反序列化文档并保留标题和段落的顺序。为了订购,我们需要一片。为了同时容纳 headp,我们需要一个接口(interface)。我们可以这样定义我们的文档:

type Document struct {
    XMLName  xml.Name `xml:"doc"`
    Contents []Mixed  `xml:",any"`
}

,any 注释会将any 元素收集到Contents 中。它是一个Mixed类型,我们需要定义为一个类型:

type Mixed struct {
    Type  string      // just keep "head" or "p" in here
    Value interface{} // keep the value, we could use string here, too
}

我们需要对反序列化过程有更多的控制,所以我们将Mixed 变成xml.Unmashaler。通过实现 UnmarshalXML。我们根据起始元素的名称来决定代码路径,例如headp。在这里,我们只用一些值填充我们的 Mixed 结构,但您基本上可以在这里做任何事情:

func (m *Mixed) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    switch start.Name.Local {
    case "head", "p":
        var e string
        if err := d.DecodeElement(&e, &start); err != nil {
            return err
        }
        m.Value = e
        m.Type = start.Name.Local
    default:
        return fmt.Errorf("unknown element: %s", start)
    }
    return nil
}

将它们放在一起,上述结构的用法可能如下所示:

func main() {
    s := `
    <doc>
        <head>My Title</head>
        <p>A first paragraph.</p>
        <p>A second one.</p>
    </doc>
    `

    var doc Document
    if err := xml.Unmarshal([]byte(s), &doc); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("#%v", doc)
}   

哪个会打印。

#{{ doc} [{head My Title} {p A first paragraph.} {p A second one.}]}

我们保留了顺序并保留了一些类型信息。您可以使用许多不同的类型来进行反序列化,而不是单一类型,例如 Mixed。这种方法的代价是您的容器(这里是文档的 Contents 字段)是一个接口(interface)。要执行任何特定于元素的操作,您需要类型断言或一些辅助方法。

完整代码:https://play.golang.org/p/fzsUPPS7py

关于xml - 以 golang 保留顺序混合 XML 解码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32187067/

相关文章:

java - 在类 'dataSource' 中找不到属性 'org.springframework.security.provisioning.JdbcUserDetailsManager' 的 setter

java - JAXB自定义命名空间前缀问题

c# - 似乎无法在 c# 中使用 XmlSerializer 反序列化非常简单的 xml

go - 在 go ( golang ) 中为 slice 结构赋值

arrays - 函数返回后,在数组的结构成员上设置的值丢失

tensorflow 通过(不同范围的 2d)切片列表更改/分配矩阵元素值

go - 如何在golang中获取随机数样本?

xml - Spring Test/JUnit 问题 - 无法加载应用程序上下文

go - 基于Go的grpc服务器流不断堆积响应以转到go客户端

xml - 将 XML 解析为包含 slice 的结构