当前位置: 首页 > 面试题库 >

我可以将Go的xml.Unmarshall用于有序多态类型吗?

周墨一
2023-03-14
问题内容

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

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>`

我想接受这一点,并从本质上讲是可以在上面运行方法的一部分。

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

我该如何使用Unmarshall呢?

编辑:也许我可以Decoder根据标签名称使用循环遍历和解组?


问题答案:

encoding/json包不同,您没有Unmarshaller接口。在您的情况下,您将必须使用Decoder自己建议的。

下面是一个可行的解决方案:

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)
        }
    }
}

输出:

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

操场

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



 类似资料:
  • 问题内容: 我想在Go中创建分层错误。我们可以在Go中实现吗?例如,我有以下两个错误。 我想要一个包含两个子类型和的错误类型,以便执行以下操作。 有办法实现吗? 编辑: 在类型切换中,我们可以使用多个错误,如下所示: 但是,当我遇到大量错误时,或者当我需要对模块内部的错误进行抽象时,这种方法将不是最好的方法。 问题答案: 您可以在中列出多个类型,这样便可以完成您想做的事情: 测试它: 输出(在Go

  • 问题内容: 有什么方法可以在使用Java Swing的应用程序中重用CSS? 问题答案: 飞碟采用XML或XHTML并对其应用符合CSS2.1的样式表,以便使用(通过iText)呈现为PDF(通过iText),图像和在屏幕上显示摇摆或SWT

  • 下面是我想与Jackson反序列化的JSON示例。 这里反序列化的棘手之处是联系人节点。需要注意的事情: contacts是一种多态抽象类型(参见下面的POJOs) 目标POJO: 注意:外部需求要求我使用抽象联系人类型。我宁愿直接反序列化到这些POJO,而不是让联系人类型挂起的中间POJO在另一个步骤中手动映射/转换到我的列表。 我已经查看了许多其他杰克逊多态反序列化问题,但似乎没有一个能处理这

  • 我知道Python主要比fortran和C/C++等语言慢,因为它是解释而不是编译的。 另一个我也读过的原因是它非常慢,因为它是动态类型的,也就是说,您不需要声明变量类型,它会自动声明。这是非常好的,因为它使代码看起来更干净,您基本上不必太担心变量类型。

  • 我想创建一个简单的Java类文件,并从我的所有项目访问它。 我知道我可以通过复制/粘贴方法来完成,但在这种情况下,类文件将独立于其原始源。我在原始类文件中所做的任何更改都不会影响已经复制到其他项目中的类文件。 在Android Studio中有链接类文件的方法吗?

  • 问题内容: 如果我有这样的类结构: 还有另一种反序列化的方法吗?在父类上使用此注释: 我不想强迫我的API的客户包括反序列化一个子类。 杰克逊不是使用,而是提供了一种方法来注释子类并通过唯一属性将其与其他子类区分开来?在上面的示例中,这类似于“如果JSON对象将其反序列化为,如果它将其反序列化为”。 问题答案: 感觉像是应该使用的东西,但是我在文档中进行了选择,可以提供的任何属性似乎都不符合您所描