Golang: Read single XML document from net.Conn

huangapple go评论89阅读模式
英文:

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 &lt;Person&gt;):

const data = `&lt;Person&gt;
	&lt;Name&gt;Bob&lt;/Name&gt;
	&lt;Age&gt;23&lt;/Age&gt;
&lt;/Person&gt;
&lt;Person&gt;
	&lt;Name&gt;Alice&lt;/Name&gt;
	&lt;Age&gt;21&lt;/Age&gt;
&lt;/Person&gt;
`

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 &lt; 2; i++ {
	p := Person{}
	if err := d.Decode(&amp;p); err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf(&quot;%+v\n&quot;, 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(&amp;p); err != nil {
		if err == io.EOF {
			fmt.Println(&quot;EOF, breaking&quot;)
			break
		}
		fmt.Println(err)
	} else {
		fmt.Printf(&quot;%+v\n&quot;, 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(&amp;doc); err != nil {
    // Handle error
    return
}
// No error, use doc:
fmt.Printf(&quot;%+v&quot;, doc)

huangapple
  • 本文由 发表于 2016年9月26日 18:47:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/39700817.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定