英文:
Golang: Read single XML document from net.Conn
问题
我有一个客户端-服务器连接。它们通过 XML 进行通信,并且在一个会话期间传输多个 XML 文档。xml.Unmarshal
需要一个字节切片,但我不能只是从套接字中读取所有字节(它会尝试读取多个 XML,从而导致阻塞)。
是否有标准的 XML 解析器或库,可以从字节流中解析,并且只读取实际需要的数据量?
英文:
I have a client-server connection. They communicate through xml and multiple xml documents are transmitted during one session. xml.Unmarshal
wants a slice of bytes, but I can't just ReadAll
all bytes from socket (it will try to read more then a single xml and therefore block).
Is there a standard xml parser or a library, that can parse from a stream of bytes and read no more data than it actually needs?
答案1
得分: 1
你可以使用标准库中的xml.Decoder
来实现这个目的。你可以使用xml.NewDecoder()
创建一个新的xml.Decoder
,它需要一个io.Reader
来读取数据。net.Conn
作为实现了io.Reader
的类型可以使用。Decoder.Decode()
方法将读取并处理一个XML文档。
让我们看一个例子。源代码包含了两个连接在一起的XML文档,我们调用Decoder.Decode()
两次来读取和解析这两个文档。
XML源代码:两个XML文档(2个<Person>
):
const data = `<Person>
<Name>Bob</Name>
<Age>23</Age>
</Person>
<Person>
<Name>Alice</Name>
<Age>21</Age>
</Person>
`
用于建模XML文档的Go结构体:
type Person struct {
Name string
Age int
}
读取这两个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
// 初始化/获取连接
d := xml.NewDecoder(con)
var doc YourDocType
if err := d.Decode(&doc); err != nil {
// 处理错误
return
}
// 没有错误,使用doc:
fmt.Printf("%+v", doc)
英文:
You may use xml.Decoder
from the standard library for this purpose. You may use xml.NewDecoder()
to create a new xml.Decoder
which expects an io.Reader
to read the data from. net.Conn
qualifies as it implements io.Reader
. The Decoder.Decode()
method will read and process 1 XML document.
Let's see an example. The source will contain 2 XML documents concatenated, and we call Decoder.Decode()
twice to read and parse those 2 documents.
The XML source: 2 XML documents (2 <Person>
):
const data = `<Person>
<Name>Bob</Name>
<Age>23</Age>
</Person>
<Person>
<Name>Alice</Name>
<Age>21</Age>
</Person>
`
Go struct to model the XML documents:
type Person struct {
Name string
Age int
}
Code to read those 2 XML documents:
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)
}
}
Output (try it on the Go Playground):
{Name:Bob Age:23}
{Name:Alice Age:21}
Note that Decoder.Decode()
will return io.EOF
if no more data is available. To read all XML documents from the input, you may do it like this:
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)
}
}
Back to your example
If you want to read XML documents transmitted over a TCP connection, you may simply pass the net.Conn
value (which implements io.Reader
) to 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论