在Go语言中实现多类型解码器

huangapple go评论107阅读模式
英文:

Multiple-types decoder in golang

问题

我有一个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"`
}

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

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

英文:

I have an XML document. Some fields have custom format. Example:

&lt;document&gt;
  &lt;title&gt;hello world&lt;/title&gt;
  &lt;lines&gt;
   line 1
   line 2
   line 3
  &lt;/lines&gt;
&lt;/document&gt;

I want to import it into structure like:

type Document struct {
	Title  string   `xml:&quot;title&quot;`
	Lines  []string `xml:&quot;lines&quot;`
}

Is there some way how to implement custom decoder, which will split lines string into array of lines ([&quot;line 1&quot;, &quot;line 2&quot;, &quot;line 3&quot;])?

Its possible to make Lines field a string type and make split after xml import, but it doesn't seems to be very elegant solution. Is there any way i can define custom decoder for line spliting and combine it with xml decoder?

答案1

得分: 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方法(构造你想要的字符串内容,并将其传递给编码器)。

英文:

You can achieve this by defining a new type that conforms to the xml.Unmarshaler interface. So rather than making Lines a []string, declare a new type with an appropriate UnmarshalXML method. For instance:

type Lines []string

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

You can see a full example here: http://play.golang.org/p/3SBu3bOGjR

If you want to support encoding this type too, you can implement the MarshalXML method in a similar fashion (construct the string content you want and pass that to the encoder).

答案2

得分: 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
}
英文:

Here is a spelled out example of what CSE is suggesting:

type Document struct {
    Title    string `xml:&quot;title&quot;`
    LineData string `xml:&quot;lines&quot;`
}

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

This is similar to what net/http Request does: read the data into a struct, and then provide accessors to interpret that struct.

If you really don't want to do that, then another approach that I have used is to create two structs. Read the raw data into the first and then use that to construct the second.

If you are planning on shipping this out as JSON or some other wire format, the second struct could just be a map.

func (d *Document) Map() map[string]interface{} {
    m := make(map[string]interface{})
    m[&quot;lines&quot;] = strings.Split(d.LineData, &#39;\n&#39;)
    m[&quot;title&quot;] = d.Title
    return m
}

huangapple
  • 本文由 发表于 2014年1月16日 22:26:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/21164455.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定