我可以使用Go的xml.Unmarshall排序多态类型吗? [英] Can I use Go's xml.Unmarshall for Ordered Polymorphic Types?

查看:110
本文介绍了我可以使用Go的xml.Unmarshall排序多态类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用Go解析和序列化xml,但它看起来像Marshall / Unmarshall只适用于结构化数据,而不适用于有序指令。我想要做这样的事情:

  type Play结构{
loops uint16
//元素体是文件名
}

类型说struct {
loops uint16
语音字符串
}

func( p * Play)Execute()(err error){
//播放文件
}

xml:=`< Root>
< Say>播放档案< / Say>
< Play loops =2> https://host/somefile.mp3< / Play>
< Say>完成播放< / Say>
< / Root>`

我想要这样做,我可以运行方法的一部分。

  for _,instruction:= range actions {
instruction.Execute ()
}

如何使用 Unmarshall



编辑:也许我可以使用解码器循环和Unmarshall每一个基于标签名称?

解决方案

encoding / json 包不同,您没有 Unmarshaller 界面。在你的情况下,你必须使用 Decoder ,正如你所建议的那样。



以下是一个工作解决方案:
$ b

package main

import(
bytes
编码/ xml
fmt


//任何指令所需的接口
类型执行接口{
Execute()错误
}

var factoryMap map [string] func()Executer = make(map [string] func()Executer)

类型播放结构{
Loops int`xml:loops,attr`
文件字符串`xml:,innerxml`
//元素体是文件名
}

func(p * Play)Execute()错误{
for i:= 0;我< p.Loops; i ++ {
fmt.Println(`o /`+ p.File)
}
返回零
}

类型说struct {
语音字符串`xml:,innerxml`
}

func(s * Say)Execute()错误{
fmt.Println(s.Voice)
返回nil
}

//让我们注册不同的指令
//你可以将每个指令结构放在不同的文件中,让每个文件都有一个init
func init(){
factoryMap [Play] = func()Executer {return new(Play)}
factoryMap [Say] = func()Executer {return new(Say)}

$ b $ func Unmarshal(b [] byte)([] Executer,error){
d:= xml.NewDecoder(bytes.NewReader(b))

var操作[]执行器

//找到第一个根标记
用于{
v,err:= d.Token()
如果err!= nil {
return nil,err
}

if _,ok:= v。(xml.StartElement); OK {
break
}
}

//循环读取其余的标记
//找到每个标记的开头。
for {
v,err:= d.Token()
if err!= nil {
return nil,err
}

switch t:= v。(type){

case xml.StartElement:
//我们找到了一条指令的开始。
//让我们在我们的factoryMap
中检查名称//您应该检查指令名称是否存在。现在它恐慌。
f:= factoryMap [t.Name.Local]
instr:= f()

//我们将标记的其余部分解码为指令struct
err := d.DecodeElement(instr,& t)
if err!= nil {
return nil,err
}

//追加填充动作
actions = append(actions,instr)

case xml.EndElement:
//我们找到Root的结束标记。我们完了!
return actions,nil
}
}
return nil,nil
}

func main(){
xml: = [] byte(`< Root>
< Say>播放文件< / Say>
< Play loops =2> https://host/somefile.mp3< / Play> ;
< Say>完成播放< / Say>
< / Root>`)

actions,err:= Unmarshal(xml)
if err! = nil {
panic(err)
}

for _,instruction:= range actions {
err = instruction.Execute()
if err != nil {
fmt.Println(err)
}
}
}

输出:

 播放文件
o / //host/somefile.mp3
o / https://host/somefile.mp3
完成播放

游乐场



当然,这个代码并不完整,但应该是足以让您清楚了解如何解决问题。


I want to parse and serialize xml with Go, but it's looking like Marshall/Unmarshall only works well for structured data and not so much for ordered instructions. I'd like to do something like this:

type Play struct {
    loops uint16
    // Body of element is file name
}

type Say struct {
    loops uint16
    voice string
}

func (p *Play) Execute() (err error) {
    // Play the file
}

xml := `<Root>
    <Say>Playing file</Say>
    <Play loops="2">https://host/somefile.mp3</Play>
    <Say>Done playing</Say>
</Root>`

I want to take that and essentially end up with a slice of these that I can run methods on.

for _, instruction := range actions {
    instruction.Execute()
}

How can I do that using Unmarshall?

EDIT: Maybe I could use the Decoder to loop through and Unmarshall each one based on the tag name?

解决方案

Unlike the encoding/json package, you have no Unmarshaller interface. In your case, you will have to use the Decoder as you have suggested yourself.

Below is a working solution:

package main

import (
    "bytes"
    "encoding/xml"
    "fmt"
)

// An interface required by any instruction
type Executer interface {
    Execute() error
}

var factoryMap map[string]func() Executer = make(map[string]func() Executer)

type Play struct {
    Loops int `xml:"loops,attr"`
    File  string `xml:",innerxml"`
    // Body of element is file name
}

func (p *Play) Execute() error {
    for i := 0; i < p.Loops; i++ {
        fmt.Println(`o/ ` + p.File)
    }
    return nil
}

type Say struct {
    Voice string `xml:",innerxml"`
}

func (s *Say) Execute() error {
    fmt.Println(s.Voice)
    return nil
}

// Let's register the different instructions
// You can have each Instruction struct in separate files, letting each file having an init
func init() {
    factoryMap["Play"] = func() Executer { return new(Play) }
    factoryMap["Say"] = func() Executer { return new(Say) }
}

func Unmarshal(b []byte) ([]Executer, error) {
    d := xml.NewDecoder(bytes.NewReader(b))

    var actions []Executer

    // Finding the first Root tag
    for {
        v, err := d.Token()
        if err != nil {
            return nil, err
        }

        if _, ok := v.(xml.StartElement); ok {
            break
        }
    }

    // Looping through the rest of the tokens
    // finding the start of each.
    for {
        v, err := d.Token()
        if err != nil {
            return nil, err
        }

        switch t := v.(type) {

        case xml.StartElement:
            // We found a start of an instruction.
            // Let's check the name in our factoryMap
            // You should check that the Instruction name actually exists. Now it panics.
            f := factoryMap[t.Name.Local]
            instr := f()

            // We decode the rest of the tag into the instruction struct
            err := d.DecodeElement(instr, &t)
            if err != nil {
                return nil, err
            }

            // Appending the populated action
            actions = append(actions, instr)

        case xml.EndElement:
            // We found the end tag of the Root. We are done!
            return actions, nil
        }
    }
    return nil, nil
}

func main() {
    xml := []byte(`<Root>
    <Say>Playing file</Say>
    <Play loops="2">https://host/somefile.mp3</Play>
    <Say>Done playing</Say>
</Root>`)

    actions, err := Unmarshal(xml)
    if err != nil {
        panic(err)
    }

    for _, instruction := range actions {
        err = instruction.Execute()
        if err != nil {
            fmt.Println(err)
        }
    }
}

Output:

Playing file  
o/ https://host/somefile.mp3  
o/ https://host/somefile.mp3  
Done playing

Playground

Of course, this code is not complete, but it should be enough to give you a clear picture on how you can solve your problem.

这篇关于我可以使用Go的xml.Unmarshall排序多态类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆