dqnqpqv3841
dqnqpqv3841
2016-09-26 10:47

Golang:从net.Conn中读取单个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条回答

  • duan19750503 duan19750503 5年前

    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
    ", 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
    ", 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)
    
    点赞 评论 复制链接分享

相关推荐