簡體   English   中英

開始:一次僅解碼一個XML節點

[英]Go: Decoding only one XML node at a time

瀏覽用於encoding / xml包的源代碼,所有解組邏輯(用於解碼實際的XML節點並鍵入它們的類型)都處於解組狀態,而調用此方法的唯一方法實質上是調用DecodeElement。 但是,解編組邏輯還固有地搜索下一個EndElement。 造成這種情況的主要原因似乎是驗證。 但是,這似乎對我來說是一個主要的設計缺陷:如果我有一個龐大的XML文件,我對該文件的結構有足夠的信心,並且我想一次解碼一個節點,以便可以高效地進行過濾,那該怎么辦?通過實時數據? RawToken()調用可用於獲取當前標簽,這很好,但是很顯然,當您在其上調用DecodeElement()時,不可避免的unmarshal()調用顯然開始以某種方式運行到節點中時會出現錯誤它被認為是不平衡的。

從理論上講,可能會遇到我要解碼,捕獲偏移量,對元素進行解碼,返回到先前位置並循環的令牌,但這仍然會導致大量不必要的處理。

有沒有辦法一次只解析一個節點?

例如,您描述的內容稱為XML流解析,因為它是由任何SAX解析器完成的。 好消息: encoding/xml支持,盡管它有點隱藏。

您實際要做的是創建xml.Decoder實例,並傳遞io.Reader 然后,您將使用Decoder.Token()讀取輸入流,直到找到下一個有效的 xml令牌。 從那里,您可以決定下一步要做什么。

這是一個可以作為gist使用的小例子,或者您可以在PlayGround上運行它

package main

import (
    "bytes"
    "encoding/xml"
    "fmt"
)

const (
    book = `<?xml version="1.0" encoding="UTF-8"?>
<book>
  <preface>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</preface>
  <chapter num="1" title="Foo">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</chapter>
  <chapter num="2" title="Bar">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</chapter>
</book>`
)

type Chapter struct {
    Num     int    `xml:"num,attr"`
    Title   string `xml:"title,attr"`
    Content string `xml:",chardata"`
}

func main() {

    // We emulate a file or network stream
    b := bytes.NewBufferString(book)

    // And set up a decoder
    d := xml.NewDecoder(b)

    for {

        // We look for the next token
        // Note that this only reads until the next positively identified
        // XML token in the stream
        t, err := d.Token()

        if err != nil  {
            break
        }

        switch et := t.(type) {

        case xml.StartElement:
            // We now have to inspect wether we are interested in the element
            // otherwise we will advance
            if et.Name.Local == "chapter" {
                // Most often/likely element first

                c := &Chapter{}

                // We decode the element into(automagically advancing the stream)
                // If no matching token is found, there will be an error
                // Note the search only happens within the parent.
                if err := d.DecodeElement(&c, &et); err != nil {
                    panic(err)
                }

                // We have found what we are interested in, so we print it
                fmt.Printf("%d: %s\n", c.Num, c.Title)

            } else if et.Name.Local == "book" {
                fmt.Println("Book begins!")
            }

        case xml.EndElement:

            if et.Name.Local != "book" {
                continue
            }

            fmt.Println("Finished processing book!")
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM