xml - 如何使用golang编码/xml读取具有不同根的xml内容

标签 xml go

我当前的当前任务是使用golang读取进入系统的不同xml负载。 xml有效负载可能具有不同的根标记名称。根标签名称不同意味着xml具有完全不同的含义。
我已经使用编码/ xml已有一段时间了,但是我发现无法通过一个Unmarshal调用来读取那些xml负载,而无需在未提取或提取根名称之前进行操作的情况下对其进行读取。 。

这是手头任务的简化示例,分别读取2个xml:

package main

import (
    "fmt"
    "encoding/xml"
)

type Boxes struct {
    Length []float64
}

type Bottles struct {
    Diameter []float64
}   

var Box_xml = []byte("<Boxes><Length>45</Length><Length>41</Length></Boxes>")
var Bottle_xml = []byte("<Bottles><Diameter>23</Diameter><Diameter>25</Diameter></Bottles>")

func main() {
    box := Boxes{}
    xml.Unmarshal(Box_xml, &box)
    bottle := Bottles{}
    xml.Unmarshal(Bottle_xml, &bottle)
    fmt.Println(box, bottle)
}

此代码打印
{[45 41]} {[23 25]}

我当前用于在单个调用中处理任意传入消息的“最佳”解决方案将是向这些xml添加一个根标记,并在中央结构中读取它们-像这样:
package main

import (
    "fmt"
    "encoding/xml"
)

type Boxes struct {
    Length []float64
}

type Bottles struct {
    Diameter []float64
}

type Delivery struct {
    Boxes Boxes
    Bottles Bottles
}   

var Box_xml = []byte("<Delivery><Boxes><Length>45</Length><Length>41</Length></Boxes></Delivery>")
var Bottle_xml = []byte("<Delivery><Bottles><Diameter>23</Diameter><Diameter>25</Diameter></Bottles></Delivery>")

func main() {
    delivery := Delivery{}
    xml.Unmarshal(Box_xml, &delivery)
    fmt.Println(delivery )
    delivery = Delivery{}
    xml.Unmarshal(Bottle_xml, &delivery)
    fmt.Println(delivery)
}

此代码打印
{{[45 41]} {[]}}
{{[]} {[23 25]}}

这将是构造结果以供以后处理的好方法。

我如何做到而不必在有效负载中添加人工根标签?

最佳答案

您可以创建xml解码器,并使用Token方法逐节点解析xml输入。它不会解析所有文档。查看更多here

token 返回输入流中的下一个XML token 。在输入流的末尾, token 返回nil,io.EOF。
返回的 token 数据中的 byte slice 引用解析器的内部缓冲区,并且仅在下一次调用Token之前保持有效。要获取字节的副本,请调用CopyToken或 token 的Copy方法。
token 将自关闭元素扩展为连续调用返回的单独的开始和结束元素。
token 保证返回的StartElement和EndElement token 正确嵌套和匹配:如果Token在所有预期的结束元素之前遇到意外的结束元素或EOF,它将返回错误。

这只是一个示例,如何确定具有的xml类型和需要解析的结构:

package main

import (
    "encoding/xml"
    "log"
    "strings"
)

type Boxes struct {
    Length []float64
}

type Bottles struct {
    Diameter []float64
}

type DeliveryBoxes struct {
    Boxes   Boxes
}

type DeliveryBottles struct {
    Bottles Bottles
}

const (
    BoxXML    = "<Delivery><Boxes><Length>45</Length><Length>41</Length></Boxes></Delivery>"
    BottleXML = "<Delivery><Bottles><Diameter>23</Diameter><Diameter>25</Diameter></Bottles></Delivery>"
)

func main() {
    var err error
    var xmlReader = strings.NewReader(BoxXML)
    var decoder = xml.NewDecoder(xmlReader)

    // start with a first token 'Delivery'
    t, err := decoder.Token()
    if err != nil {
        log.Fatalln(err)
    }

    // next token is a next node: 'Boxes' or 'Bottles'
    t, err = decoder.Token()
    if err != nil {
        log.Fatalln(err)
    }

    startElement := t.(xml.StartElement)

    // create new reader to start from the beginning
    xmlReader = strings.NewReader(BoxXML)

    switch startElement.Name.Local {
    case "Boxes":
        var delivery DeliveryBoxes
        if err := xml.NewDecoder(xmlReader).Decode(&delivery); err != nil {
            log.Fatalln(err)
        }
        log.Println(delivery)
    case "Bottles":
        var delivery DeliveryBottles
        if err := xml.NewDecoder(xmlReader).Decode(&delivery); err != nil {
            log.Fatalln(err)
        }
        log.Println(delivery)
    }
}
通常,我们解析前两个节点以检查结构类型,然后使用定义的结构解析完整的xml输入。您可以将switch语句移至单个函数,并将interface{}类型用于delivery变量。无论如何,这是一个向您展示可以确定xml输入的数据格式而无需解析整个输入的示例。

关于xml - 如何使用golang编码/xml读取具有不同根的xml内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60324774/

相关文章:

python - ValidateError 验证字段 arch 时发生错误 : Invalid XML for View Architecture

java - 自定义样式 setDropDownViewResource Android Spinner

xml - 使用 XSLT 将 KML 拆分为子文件,几乎在那里,但无法使其工作

go - 如何在 Go 中复制接口(interface)值?

go - 将接口(interface)断言为其类型

xml - 我如何在我的 xslt 代码中不重复重复的逻辑?

c# - 如何强制 WPF ListView 重新查询它的 ItemSsource?

go - 如何在运行时读取文本文件

go - 不能将接口(interface)的实现用作需要接口(interface)的 func 的参数

google-app-engine - 使用环境变量将值传递给 App Engine 上的 Go 应用程序