Golang:从net.Conn中读取单个XML文档

时间:2016-09-26 10:47:21

标签: xml parsing networking go xml-parsing

我有一个客户端 - 服务器连接。它们通过xml进行通信,并在一个会话期间传输多个xml文档。 xml.Unmarshal需要一片字节,但我不能只是ReadAll来自套接字的所有字节(它会尝试读取多个单个xml,因此阻塞)。

是否有标准的xml解析器或库,它可以从字节流中解析并且不会读取实际需要的数据?

1 个答案:

答案 0 :(得分:1)

您可以使用标准库中的xml.Decoder来实现此目的。您可以使用xml.NewDecoder()创建新的xml.Decoder,期望io.Reader从中读取数据。 net.Conn符合实施io.Reader的条件。 Decoder.Decode()方法将读取并处理1个XML文档。

让我们看一个例子。源代码将包含两个连接的XML文档,我们两次调用Decoder.Decode()来读取和解析这两个文档。

XML源:2个XML文档(2 <Person>):

const data = `<Person>
    <Name>Bob</Name>
    <Age>23</Age>
</Person>
<Person>
    <Name>Alice</Name>
    <Age>21</Age>
</Person>
`

使用struct来为XML文档建模:

type Person struct {
    Name string
    Age  int
}

读取这2个XML文档的代码:

buf := bytes.NewBuffer([]byte(data))
d := xml.NewDecoder(buf)

for i := 0; i < 2; i++ {
    p := Person{}
    if err := d.Decode(&p); err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("%+v\n", p)
    }
}

输出(在Go Playground上尝试):

{Name:Bob Age:23}
{Name:Alice Age:21}

请注意,如果没有更多可用数据,Decoder.Decode()将返回io.EOF。要从输入中读取所有XML文档,您可以这样做:

for {
    p := Person{}
    if err := d.Decode(&p); err != nil {
        if err == io.EOF {
            fmt.Println("EOF, breaking")
            break
        }
        fmt.Println(err)
    } else {
        fmt.Printf("%+v\n", p)
    }
}

回到你的例子

如果您想阅读通过TCP连接传输的XML文档,您可以简单地将net.Conn值(实现io.Reader)传递给xml.NewDecoder()

var con net.Conn
// Initialize / obtain connection

d := xml.NewDecoder(con)
var doc YourDocType
if err := d.Decode(&doc); err != nil {
    // Handle error
    return
}
// No error, use doc:
fmt.Printf("%+v", doc)