golang進(jìn)行xml文件解析的操作方法
查閱了些資料自己記錄一下
一、小文件簡(jiǎn)單解析
對(duì)于小文件的 XML 解析,我們可以使用 Go 標(biāo)準(zhǔn)庫(kù)中的encoding/xml
包來(lái)實(shí)現(xiàn)。
假設(shè)我們有一個(gè)名為demo.xml
的文件,內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?> <config> <smtpServer>smtp.163.com</smtpServer> <smtpPort>25</smtpPort> <sender>user@163.com</sender> <senderPasswd>123456</senderPasswd> <receivers flag="true"> <age>16</age> <user>Mike_Zhang@live.com</user> <user>test1@qq.com</user> <script> <![CDATA[ function matchwo(a,b) { if (a < b && a < 0) then { return 1; } else { return 0; } } ]]> </script> </receivers> </config>
對(duì)應(yīng)的main.go
文件代碼如下:
package main import ( "fmt" "io/ioutil" "encoding/xml" ) // 定義結(jié)構(gòu)體來(lái)映射 XML 結(jié)構(gòu) type SConfig struct { XMLName xml.Name `xml:"config"` SmtpServer string `xml:"smtpServer"` SmtpPort int `xml:"smtpPort"` Sender string `xml:"sender"` SenderPasswd string `xml:"senderPasswd"` Receivers SReceivers `xml:"receivers"` } type SReceivers struct { Age int `xml:"age"` Flag string `xml:"flag,attr"` User []string `xml:"user"` Script string `xml:"script"` } func readXml(path string) { // 直接讀取文件內(nèi)容,ioutil 內(nèi)部處理打開(kāi)和關(guān)閉操作 data, err := ioutil.ReadFile(path) if err!= nil { fmt.Println("讀文件出錯(cuò)!", err) return } // 初始化結(jié)構(gòu)體變量 v := SConfig{} err = xml.Unmarshal(data, &v) if err!= nil { fmt.Printf("error: %v", err) return } // 打印解析后的結(jié)果 fmt.Println("SmtpServer : ", v.SmtpServer) fmt.Println("SmtpPort : ", v.SmtpPort) fmt.Println("Sender : ", v.Sender) fmt.Println("SenderPasswd : ", v.SenderPasswd) fmt.Println("Receivers.Flag : ", v.Receivers.Flag) fmt.Println("Receivers.Age : ", v.Receivers.Age) fmt.Println("Receivers.Script : ", v.Receivers.Script) for i, element := range v.Receivers.User { fmt.Println(i, element) } } func main() { readXml("demo.xml") }
運(yùn)行這段代碼后,輸出如下:
SmtpServer : smtp.163.com
SmtpPort : 25
Sender : user@163.com
SenderPasswd : 123456
Receivers.Flag : true
Receivers.Age : 16
Receivers.Script :function matchwo(a,b) {
if (a < b && a < 0) then {
return 1;
} else {
return 0;
}
}0 Mike_Zhang@live.com
1 test1@qq.com
二、大文件解析
當(dāng)處理較大的 XML 文件時(shí),我們可以采用流式解析的方式,以避免一次性將整個(gè)文件加載到內(nèi)存中。
同樣以demo.xml
文件為例,內(nèi)容不變。
main.go
文件代碼如下:
package main import ( "fmt" "encoding/xml" "bufio" "os" "io" ) // 定義結(jié)構(gòu)體來(lái)映射 XML 結(jié)構(gòu) type SConfig struct { XMLName xml.Name `xml:"config"` SmtpServer string `xml:"smtpServer"` SmtpPort int `xml:"smtpPort"` Sender string `xml:"sender"` SenderPasswd string `xml:"senderPasswd"` Receivers SReceivers `xml:"receivers"` } type SReceivers struct { Age int `xml:"age"` Flag string `xml:"flag,attr"` User []string `xml:"user"` Script string `xml:"script"` } func readXml(path string) { // 打開(kāi)文件 file, errOpen := os.Open(path) if errOpen!= nil { fmt.Println("打開(kāi)文件異常!", errOpen) return } defer file.Close() // 創(chuàng)建帶緩存的 Reader reader := bufio.NewReader(file) decoder := xml.NewDecoder(reader) for t, err := decoder.Token(); err == nil || err == io.EOF; t, err = decoder.Token() { switch token := t.(type) { case xml.StartElement: name := token.Name.Local fmt.Println(name) if name == "config" { // 解析 config var sConfig = SConfig{} configErr := decoder.DecodeElement(&sConfig, &token) if configErr!= nil { fmt.Println("解析錯(cuò)誤:") fmt.Println(configErr) } else { fmt.Println(sConfig) } return } } } } func main() { readXml("demo.xml") }
輸出結(jié)果為:
config
{{ config} smtp.163.com 25 user@163.com 123456 {16 true [Mike_Zhang@live.com test1@qq.com]function matchwo(a,b) {
if (a < b && a < 0) then {
return 1;
} else {
return 0;
}
}}}
三、復(fù)雜結(jié)構(gòu)解析
對(duì)于復(fù)雜結(jié)構(gòu)的 XML 文件,我們可以使用第三方庫(kù)github.com/beevik/etree
來(lái)進(jìn)行解析。
假設(shè)我們有一個(gè)名為bookstores.xml
的文件,內(nèi)容如下:
<bookstore xmlns:p="urn:schemas-books-com:prices"> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <p:price>30.00</p:price> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <p:price>29.99</p:price> </book> <book category="WEB"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <author>Kurt Cagle</author> <author>James Linn</author> <author>Vaidyanathan Nagarajan</author> <year>2003</year> <p:price>49.99</p:price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <p:price>39.95</p:price> </book> </bookstore>
main.go
文件代碼如下:
package main import ( "fmt" "github.com/beevik/etree" ) func readXml(path string) { doc := etree.NewDocument() if err := doc.ReadFromFile(path); err!= nil { panic(err) } root := doc.SelectElement("bookstore") fmt.Println("ROOT element:", root.Tag) for _, book := range root.SelectElements("book") { fmt.Println("CHILD element:", book.Tag) if title := book.SelectElement("title"); title!= nil { lang := title.SelectAttrValue("lang", "unknown") fmt.Printf(" TITLE: %s (%s)\n", title.Text(), lang) } for _, attr := range book.Attr { fmt.Printf(" ATTR: %s=%s\n", attr.Key, attr.Value) } } } func main() { readXml("bookstores.xml") }
輸出結(jié)果為:
ROOT element: bookstore
CHILD element: book
TITLE: Everyday Italian (en)
ATTR: category=COOKING
CHILD element: book
TITLE: Harry Potter (en)
ATTR: category=CHILDREN
CHILD element: book
TITLE: XQuery Kick Start (en)
ATTR: category=WEB
CHILD element: book
TITLE: Learning XML (en)
ATTR: category=WEB
使用流數(shù)據(jù)進(jìn)行解析xml文件如果所包含標(biāo)簽存在會(huì)有字段讀取丟失清空這種情況進(jìn)行如下編寫(xiě)
package main import ( "encoding/xml" "fmt" "io" "os" ) // 定義結(jié)構(gòu)體來(lái)映射HTML片段中的pre標(biāo)簽 type HTMLPre struct { XMLName xml.Name `xml:"htmlpre"` Text string `xml:",innerxml"` } // 定義結(jié)構(gòu)體來(lái)映射Rule元素 type XCCDFRule struct { XMLName xml.Name `xml:"Rule"` ID string `xml:"id,attr"` Title string `xml:"title"` Description string `xml:"description"` HTMLPre []HTMLPre `xml:"htmlpre"` } func parseRule(reader io.Reader) (*XCCDFRule, error) { decoder := xml.NewDecoder(reader) decoder.Strict = false decoder.AutoClose = xml.HTMLAutoClose decoder.Entity = xml.HTMLEntity var rule XCCDFRule for { token, err := decoder.Token() if err == io.EOF { break } else if err!= nil { return nil, err } switch se := token.(type) { case xml.StartElement: if se.Name.Local == "Rule" { if err := decoder.DecodeElement(&rule, &se); err!= nil { return nil, err } // 進(jìn)一步解析description中的HTML內(nèi)容 if err!= nil { return nil, err } return &rule, nil } } } return nil, fmt.Errorf("Rule element not found") } func main() { file, err := os.Open("your_file.xml") if err!= nil { fmt.Println("打開(kāi)文件錯(cuò)誤:", err) return } defer file.Close() rule, err := parseRule(file) if err!= nil { fmt.Println("解析錯(cuò)誤:", err) return } fmt.Printf("規(guī)則ID: %s\n", rule.ID) fmt.Printf("規(guī)則標(biāo)題: %s\n", rule.Title) fmt.Printf("規(guī)則描述: %s\n", rule.Description) }
在這個(gè)改進(jìn)后的代碼中:
- 定義了
HTMLPre
結(jié)構(gòu)體來(lái)映射<htmlpre>
標(biāo)簽的內(nèi)容,包括標(biāo)簽內(nèi)的文本(使用xml:",innerxml"
來(lái)獲取標(biāo)簽內(nèi)的所有XML內(nèi)容作為字符串)。 - 在
XCCDFRule
結(jié)構(gòu)體中添加了HTMLPre
字段來(lái)存儲(chǔ)解析后的<htmlpre>
標(biāo)簽內(nèi)容列表。 - 在
parseRule
函數(shù)中,解碼Rule
元素后,調(diào)用parseDescription
函數(shù)來(lái)進(jìn)一步解析description
字段中的HTML內(nèi)容,提取<htmlpre>
標(biāo)簽內(nèi)的文本并存儲(chǔ)到rule.HTMLPre
列表中。 parseDescription
函數(shù)創(chuàng)建了一個(gè)新的XML解析器來(lái)解析description
字符串中的內(nèi)容,專門(mén)查找<html:pre>
標(biāo)簽并解碼其內(nèi)容。
請(qǐng)注意,這只是一種處理方式,根據(jù)你的實(shí)際需求,可能需要進(jìn)一步調(diào)整和擴(kuò)展代碼來(lái)處理XML中更復(fù)雜的HTML嵌套結(jié)構(gòu)或其他類型的內(nèi)容。同時(shí),將"your_file.xml"
替換為實(shí)際的XML文件路徑。
到此這篇關(guān)于golang進(jìn)行xml文件解析的文章就介紹到這了,更多相關(guān)golang xml文件解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GO語(yǔ)言協(xié)程互斥鎖Mutex和讀寫(xiě)鎖RWMutex用法實(shí)例詳解
這篇文章主要介紹了GO語(yǔ)言協(xié)程互斥鎖Mutex和讀寫(xiě)鎖RWMutex用法詳解,需要的朋友可以參考下2022-04-04Go檢查結(jié)構(gòu)體中是否存在某個(gè)字段及創(chuàng)建結(jié)構(gòu)體切片或映射
這篇文章主要為大家介紹了Go檢查結(jié)構(gòu)體中是否存在某個(gè)字段及創(chuàng)建結(jié)構(gòu)體切片或映射實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01使用client-go工具調(diào)用kubernetes API接口的教程詳解(v1.17版本)
這篇文章主要介紹了使用client-go工具調(diào)kubernetes API接口(v1.17版本),本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08go?zero微服務(wù)實(shí)戰(zhàn)處理每秒上萬(wàn)次的下單請(qǐng)求
這篇文章主要為大家介紹了go?zero微服務(wù)實(shí)戰(zhàn)處理每秒上萬(wàn)次的下單請(qǐng)求示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07