go标准库的学习-encoding/xml
參考:https://studygolang.com/pkgdoc
導(dǎo)入方式:
import "encoding/xml"實(shí)現(xiàn)的簡(jiǎn)單的理解XML命名空間的XML 1.0編譯器
?
func?Unmarshal —— 用于解析XML文件
func Unmarshal(data []byte, v interface{}) errorUnmarshal解析XML編碼的數(shù)據(jù)并將結(jié)果存入v指向的值。v只能指向結(jié)構(gòu)體、切片或者和字符串。良好格式化的數(shù)據(jù)如果不能存入v,會(huì)被丟棄。
因?yàn)閁nmarshal使用reflect包,它只能填寫導(dǎo)出字段。本函數(shù)好似用大小寫敏感的比較來(lái)匹配XML元素名和結(jié)構(gòu)體的字段名/標(biāo)簽鍵名。
Unmarshal函數(shù)使用如下規(guī)則將XML元素映射到結(jié)構(gòu)體字段上。這些規(guī)則中,字段標(biāo)簽指的是結(jié)構(gòu)體字段的標(biāo)簽鍵'xml'對(duì)應(yīng)的值(參見(jiàn)上面的例子):
* 如果結(jié)構(gòu)體字段的類型為字符串或者[]byte,且標(biāo)簽為",innerxml",Unmarshal函數(shù)直接將對(duì)應(yīng)原始XML文本寫入該字段,其余規(guī)則仍適用。 * 如果結(jié)構(gòu)體字段類型為xml.Name且名為XMLName,Unmarshal會(huì)將元素名寫入該字段 * 如果字段XMLName的標(biāo)簽的格式為"name"或"namespace-URL name",XML元素必須有給定的名字(以及可選的名字空間),否則Unmarshal會(huì)返回錯(cuò)誤。 * 如果XML元素的屬性的名字匹配某個(gè)標(biāo)簽",attr"為字段的字段名,或者匹配某個(gè)標(biāo)簽為"name,attr"的字段的標(biāo)簽名,Unmarshal會(huì)將該屬性的值寫入該字段。 * 如果XML元素包含字符數(shù)據(jù),該數(shù)據(jù)會(huì)存入結(jié)構(gòu)體中第一個(gè)具有標(biāo)簽",chardata"的字段中,該字段可以是字符串類型或者[]byte類型。如果沒(méi)有這樣的字段,字符數(shù)據(jù)會(huì)丟棄。 * 如果XML元素包含注釋,該數(shù)據(jù)會(huì)存入結(jié)構(gòu)體中第一個(gè)具有標(biāo)簽",comment"的字段中,該字段可以是字符串類型或者[]byte類型。如果沒(méi)有這樣的字段,字符數(shù)據(jù)會(huì)丟棄。 * 如果XML元素包含一個(gè)子元素,其名稱匹配格式為"a"或"a>b>c"的標(biāo)簽的前綴,反序列化會(huì)深入XML結(jié)構(gòu)中尋找具有指定名稱的元素,并將最后端的元素映射到該標(biāo)簽所在的結(jié)構(gòu)體字段。以">"開(kāi)始的標(biāo)簽等價(jià)于以字段名開(kāi)始并緊跟著">" 的標(biāo)簽。 * 如果XML元素包含一個(gè)子元素,其名稱匹配某個(gè)結(jié)構(gòu)體類型字段的XMLName字段的標(biāo)簽名,且該結(jié)構(gòu)體字段本身沒(méi)有顯式指定標(biāo)簽名,Unmarshal會(huì)將該元素映射到該字段。 * 如果XML元素的包含一個(gè)子元素,其名稱匹配夠格結(jié)構(gòu)體字段的字段名,且該字段沒(méi)有任何模式選項(xiàng)(",attr"、",chardata"等),Unmarshal會(huì)將該元素映射到該字段。 * 如果XML元素包含的某個(gè)子元素不匹配以上任一條,而存在某個(gè)字段其標(biāo)簽為",any",Unmarshal會(huì)將該元素映射到該字段。 * 匿名字段被處理為其字段好像位于外層結(jié)構(gòu)體中一樣。 * 標(biāo)簽為"-"的結(jié)構(gòu)體字段永不會(huì)被反序列化填寫。Unmarshal函數(shù)將XML元素寫入string或[]byte時(shí),會(huì)將該元素的字符數(shù)據(jù)串聯(lián)起來(lái)作為值,目標(biāo)[]byte不能是nil。
Unmarshal函數(shù)將屬性寫入string或[]byte時(shí),會(huì)將屬性的值以字符串/切片形式寫入。
Unmarshal函數(shù)將XML元素寫入切片時(shí),會(huì)將切片擴(kuò)展并將XML元素的子元素映射入新建的值里。
Unmarshal函數(shù)將XML元素/屬性寫入bool值時(shí),會(huì)將對(duì)應(yīng)的字符串轉(zhuǎn)化為布爾值。
Unmarshal函數(shù)將XML元素/屬性寫入整數(shù)或浮點(diǎn)數(shù)類型時(shí),會(huì)將對(duì)應(yīng)的字符串解釋為十進(jìn)制數(shù)字。不會(huì)檢查溢出。
Unmarshal函數(shù)將XML元素寫入xml.Name類型時(shí),會(huì)記錄元素的名稱。
Unmarshal函數(shù)將XML元素寫入指針時(shí),會(huì)申請(qǐng)一個(gè)新值并將XML元素映射入該值。
舉例:
xml文件為:
<?xml version="1.0" encoding="utf-8"?> <servers version="1"><server><serverName>Shanghai_VPN</serverName><serverIP>127.0.0.1</serverIP></server><server><serverName>Beijing_VPN</serverName><serverIP>127.0.0.2</serverIP></server> </servers>舉例:
package main import("fmt""encoding/xml""io/ioutil""os""log" ) type Recurlyservers struct {//后面的內(nèi)容是struct tag,標(biāo)簽,是用來(lái)輔助反射的XMLName xml.Name `xml:"servers"` //將元素名寫入該字段Version string `xml:"version,attr"` //將version該屬性的值寫入該字段Svs []server `xml:"server"`Description string `xml:",innerxml"` //Unmarshal函數(shù)直接將對(duì)應(yīng)原始XML文本寫入該字段 }type server struct{XMLName xml.Name `xml:"server"`ServerName string `xml:"serverName"`ServerIP string `xml:"serverIP"` } func main() {file, err := os.Open("servers.xml")if err != nil {log.Fatal(err)}defer file.Close()data, err := ioutil.ReadAll(file)if err != nil {log.Fatal(err)}v := Recurlyservers{}err = xml.Unmarshal(data, &v)if err != nil {log.Fatal(err)}fmt.Println(v) fmt.Printf("XMLName: %#v\n", v.XMLName)fmt.Printf("Version: %q\n", v.Version)fmt.Printf("Server: %v\n", v.Svs)for i, svs := range v.Svs{fmt.Println(i)fmt.Printf("Server XMLName: %#v\n", svs.XMLName)fmt.Printf("Server ServerName: %q\n", svs.ServerName)fmt.Printf("Server ServerIP: %q\n", svs.ServerIP) }fmt.Printf("Description: %q\n", v.Description)}返回:
userdeMBP:go-learning user$ go run test.go {{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}] <server><serverName>Shanghai_VPN</serverName><serverIP>127.0.0.1</serverIP></server><server><serverName>Beijing_VPN</serverName><serverIP>127.0.0.2</serverIP></server> } XMLName: xml.Name{Space:"", Local:"servers"} Version: "1" Server: [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}] 0 Server XMLName: xml.Name{Space:"", Local:"server"} Server ServerName: "Shanghai_VPN" Server ServerIP: "127.0.0.1" 1 Server XMLName: xml.Name{Space:"", Local:"server"} Server ServerName: "Beijing_VPN" Server ServerIP: "127.0.0.2" Description: "\n <server>\n <serverName>Shanghai_VPN</serverName>\n <serverIP>127.0.0.1</serverIP>\n </server>\n <server>\n <serverName>Beijing_VPN</serverName>\n <serverIP>127.0.0.2</serverIP>\n </server>\n"?
生成XML文件使用下面的兩個(gè)函數(shù):
func?Marshal
func Marshal(v interface{}) ([]byte, error)Marshal函數(shù)返回v的XML編碼。
Marshal處理數(shù)組或者切片時(shí)會(huì)序列化每一個(gè)元素。Marshal處理指針時(shí),會(huì)序列化其指向的值;如果指針為nil,則啥也不輸出。Marshal處理接口時(shí),會(huì)序列化其內(nèi)包含的具體類型值,如果接口值為nil,也是不輸出。Marshal處理其余類型數(shù)據(jù)時(shí),會(huì)輸出一或多個(gè)包含數(shù)據(jù)的XML元素。
XML元素的名字按如下優(yōu)先順序獲取:
- 如果數(shù)據(jù)是結(jié)構(gòu)體,其XMLName字段的標(biāo)簽 - 類型為xml.Name的XMLName字段的值 - 數(shù)據(jù)是某結(jié)構(gòu)體的字段,其標(biāo)簽 - 數(shù)據(jù)是某結(jié)構(gòu)體的字段,其字段名 - 被序列化的類型的名字一個(gè)結(jié)構(gòu)體的XML元素包含該結(jié)構(gòu)體所有導(dǎo)出字段序列化后的元素,有如下例外:
- XMLName字段,如上所述,會(huì)省略 - 具有標(biāo)簽"-"的字段會(huì)省略 - 具有標(biāo)簽"name,attr"的字段會(huì)成為該XML元素的名為name的屬性 - 具有標(biāo)簽",attr"的字段會(huì)成為該XML元素的名為字段名的屬性 - 具有標(biāo)簽",chardata"的字段會(huì)作為字符數(shù)據(jù)寫入,而非XML元素 - 具有標(biāo)簽",innerxml"的字段會(huì)原樣寫入,而不會(huì)經(jīng)過(guò)正常的序列化過(guò)程 - 具有標(biāo)簽",comment"的字段作為XML注釋寫入,而不經(jīng)過(guò)正常的序列化過(guò)程,該字段內(nèi)不能有"--"字符串 - 標(biāo)簽中包含"omitempty"選項(xiàng)的字段如果為空值會(huì)省略空值為false、0、nil指針、nil接口、長(zhǎng)度為0的數(shù)組、切片、映射 - 匿名字段(其標(biāo)簽無(wú)效)會(huì)被處理為其字段是外層結(jié)構(gòu)體的字段如果一個(gè)字段的標(biāo)簽為"a>b>c",則元素c將會(huì)嵌套進(jìn)其上層元素a和b中。如果該字段相鄰的字段標(biāo)簽指定了同樣的上層元素,則會(huì)放在同一個(gè)XML元素里。
參見(jiàn)MarshalIndent的例子。如果要求Marshal序列化通道、函數(shù)或者映射會(huì)返回錯(cuò)誤。
func?MarshalIndent
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)MarshalIndent功能類似Marshal。但每個(gè)XML元素會(huì)另起一行并縮進(jìn),該行以prefix起始,后跟一或多個(gè)indent的拷貝(根據(jù)嵌套層數(shù))。它只是多了縮進(jìn)的設(shè)定,使得生成的XML文件可讀性更高
兩個(gè)函數(shù)第一個(gè)參數(shù)是用來(lái)生成XML的結(jié)構(gòu)定義類型數(shù)據(jù),都是返回生成的XML數(shù)據(jù)流
舉例生成上面解析的XML文件:
package main import("fmt""encoding/xml" "os" ) type Servers struct {//后面的內(nèi)容是struct tag,標(biāo)簽,是用來(lái)輔助反射的 XMLName xml.Name `xml:"servers"` //將元素名寫入該字段 Version string `xml:"version,attr"` //將version該屬性的值寫入該字段 Svs []server `xml:"server"` } type server struct{ ServerName string `xml:"serverName"` ServerIP string `xml:"serverIP"` } func main() { v := &Servers{Version : "1"} v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"}) v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"}) //每個(gè)XML元素會(huì)另起一行并縮進(jìn),每行以prefix(這里為兩個(gè)空格)起始,后跟一或多個(gè)indent(這里為四個(gè)空格)的拷貝(根據(jù)嵌套層數(shù)) //即第一層嵌套只遞進(jìn)四個(gè)空格,第二層嵌套則遞進(jìn)八個(gè)空格 output, err := xml.MarshalIndent(v," ", " ") if err != nil{ fmt.Printf("error : %v\n", err) } os.Stdout.Write([]byte(xml.Header)) //輸出預(yù)定義的xml頭 <?xml version="1.0" encoding="UTF-8"?> os.Stdout.Write(output) }返回:
userdeMBP:go-learning user$ go run test.go <?xml version="1.0" encoding="UTF-8"?> <servers version="1"> <server> <serverName>Shanghai_VPN</serverName> <serverIP>127.0.0.1</serverIP> </server> <server> <serverName>Beijing_VPN</serverName> <serverIP>127.0.0.2</serverIP> </server> </servers>需要os.Stdout.Write([]byte(xml.Header))這句代碼是因?yàn)樯厦娴膬蓚€(gè)函數(shù)輸出的信息都是不帶XML頭的,為了生成正確的xml文件,需要使用xml包預(yù)定義的Header變量
?
Constants?
?
const (// 適用于本包Marshal輸出的一般性XML header// 本常數(shù)并不會(huì)自動(dòng)添加到本包的輸出里,這里提供主要是出于便利的目的Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n" )?
?
另一個(gè)例子:
package main import("fmt""encoding/xml" "os" ) type Address struct { City, State string } type Person struct { XMLName xml.Name `xml:"person"` //該XML文件的根元素為person Id int `xml:"id,attr"` //該值會(huì)作為person元素的屬性 FirstName string `xml:"name>first"` //first為name的子元素 LastName string `xml:"name>last"` //last Age int `xml:"age"` Height float32 `xml:"height,omitempty"` //含omitempty選項(xiàng)的字段如果為空值會(huì)省略 Married bool //默認(rèn)為false Address //匿名字段(其標(biāo)簽無(wú)效)會(huì)被處理為其字段是外層結(jié)構(gòu)體的字段,所以沒(méi)有Address這個(gè)元素,而是直接顯示City, State這兩個(gè)元素 Comment string `xml:",comment"` //注釋 } func main() { v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} v.Comment = " Need more details. " v.Address = Address{"Hanga Roa", "Easter Island"} output, err := xml.MarshalIndent(v, " ", " ") if err != nil { fmt.Printf("error: %v\n", err) } os.Stdout.Write(output) }返回:
userdeMBP:go-learning user$ go run test.go<person id="13"><name><first>John</first><last>Doe</last></name><age>42</age><Married>false</Married> <City>Hanga Roa</City> <State>Easter Island</State> <!-- Need more details. --> </person>如果是用的是xml.Marshal(v),返回為:
userdeMBP:go-learning user$ go run test.go <person id="13"><name><first>John</first><last>Doe</last></name><age>42</age><Married>false</Married><City>Hanga Roa</City><State>Easter Island</State><!-- Need more details. --></person>可讀性就會(huì)變得差很多
?未完待續(xù)
轉(zhuǎn)載于:https://www.cnblogs.com/wanghui-garcia/p/10430013.html
總結(jié)
以上是生活随笔為你收集整理的go标准库的学习-encoding/xml的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 云主机与虚拟主机有何区别
- 下一篇: containerd项目正式从CNCF毕