用Go语言实现多类型解码器

4

我有一个XML文档。一些字段具有自定义格式。例如:

<document>
  <title>hello world</title>
  <lines>
   line 1
   line 2
   line 3
  </lines>
</document>

我希望将它导入到如下结构中:
type Document struct {
    Title  string   `xml:"title"`
    Lines  []string `xml:"lines"`
}

有没有一种方法可以实现自定义解码器,将行字符串拆分成行数组(["line 1", "line 2", "line 3"])?

可以将Lines字段设置为字符串类型,并在xml导入后进行拆分,但这似乎不是很优雅的解决方案。是否有任何方法可以定义自定义解码器以进行行拆分,并将其与xml解码器组合使用?


不按照规则:http://golang.org/pkg/encoding/xml/#Unmarshal。它总是将其映射到一个字符串。对于XML解析器来说,触及这些行没有任何意义,因为它们不是XML结构的一部分。为什么不通过添加方法自己打破这些行呢? - 0x434D53
2个回答

7

您可以通过定义符合 xml.Unmarshaler 接口的新类型来实现这一点。因此,不要将 Lines 声明为 []string,而是声明一个具有适当的 UnmarshalXML 方法的新类型。例如:

type Lines []string

func (l *Lines) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    var content string
    if err := d.DecodeElement(&content, &start); err != nil {
        return err
    }
    *l = strings.Split(content, "\n")
    return nil
}

您可以在此处查看完整示例:http://play.golang.org/p/3SBu3bOGjR

如果您想支持编码此类型,可以以类似的方式实现MarshalXML方法(构造所需的字符串内容并将其传递给编码器)。


0

这里是一个详细的例子,说明了CSE建议的内容:

type Document struct {
    Title    string `xml:"title"`
    LineData string `xml:"lines"`
}

func (d *Document)Lines() []string {
    return strings.Split(d.LineData, '\n')
}

这与net/http Request所做的类似:将数据读入结构体,然后提供访问器以解释该结构。
如果您真的不想这样做,那么我使用的另一种方法是创建两个结构体。将原始数据读入第一个结构体,然后使用该结构体来构建第二个结构体。
如果您计划将其作为JSON或其他线路格式发送,第二个结构体可以是一个映射。
func (d *Document) Map() map[string]interface{} {
    m := make(map[string]interface{})
    m["lines"] = strings.Split(d.LineData, '\n')
    m["title"] = d.Title
    return m
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接