xml包中并不支持某些數(shù)據(jù)類型的XML序列化和反序列化,例如對(duì)map[string]string類型就不支持坯癣,此時(shí)我們可以自行編寫編解碼函數(shù)來補(bǔ)充上對(duì)這種類型的支持霍比。
package main
import (
? "encoding/xml"
? "io"
? t "tools"
)
type StringMap map[string]string
type xmlMapEntry struct {
? XMLName xml.Name
? Value??string `xml:",chardata"`
}
func (va StringMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
? if len(va) == 0 {
?????? return nil
? }
? errT := e.EncodeToken(start)
? if errT != nil {
?????? return errT
? }
? for k, v := range va {
?????? e.Encode(xmlMapEntry{XMLName:xml.Name{Local: k}, Value: v})
? }
? errT = e.EncodeToken(start.End())
? e.Flush()
? return errT
}
func (p *StringMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
? *p = StringMap{}
? for {
?????? var e xmlMapEntry
?????? errT := d.Decode(&e)
?????? if errT == io.EOF {
???????????? break
?????? } else if errT != nil {
???????????? return errT
?????? }
?????? (*p)[e.XMLName.Local] = e.Value
? }
? return nil
}
type Students struct {
? Student []StringMap
}
func main() {
? map1T := StringMap{"Name": "小明", "Age": "11", "Gender": "男"}
? map2T := StringMap{"Name": "小紅", "Age": "9", "Gender": "女"}
? students1T := &Students{Student:[]StringMap{map1T, map2T}}
? bytesT, errT := xml.MarshalIndent(students1T,"", "? ")
? if errT != nil {
?????? t.Printfln("XML編碼時(shí)發(fā)生錯(cuò)誤: %v", errT.Error())
?????? return
? }
? t.Printfln("XML: %v",string(bytesT))
? students2T := new(Students)
? errT = xml.Unmarshal(bytesT, &students2T)
? if errT != nil {
?????? t.Printfln("XML解碼時(shí)發(fā)生錯(cuò)誤: %v", errT.Error())
?????? return
? }
? t.Printfln("students2T: %#v",students2T)
}
代碼 10?5 支持map[string]string類型的XML序列化和反序列化
代碼10?5中完整演示了自定義XML編解碼函數(shù)以支持map[string]string類型的序列化和反序列過程腊脱。
-> 首先土砂,我們自定義了一個(gè)類型StringMap,它實(shí)質(zhì)上就是map[string]string類型氮凝,但由于Go語言中不允許在內(nèi)置數(shù)據(jù)類型上定義成員函數(shù)羔巢,所以我們只能用這種方法來新建一個(gè)類型;
->?代碼中StringMap自定義編碼時(shí)用到EncodeToken來寫入包含本字段內(nèi)容的XML標(biāo)簽名,調(diào)用了這個(gè)函數(shù)后竿秆,最好要調(diào)用Encoder.Flush函數(shù)來確保寫入動(dòng)作完畢炭臭;
->?xmlMapEntry結(jié)構(gòu)類型是我們用來進(jìn)行XML編碼時(shí)保存map[string]string中的鍵值對(duì)的專用結(jié)構(gòu),我們會(huì)將鍵名存在該結(jié)構(gòu)中xml.Name類型的字段XMLName的成員變量Local中袍辞,該鍵名對(duì)應(yīng)的數(shù)值則存在xmlMapEntry.Value字段中鞋仍;解碼時(shí)則反向從其中獲取鍵值對(duì);
->?Students結(jié)構(gòu)是為了演示存在多個(gè)StringMap類型的數(shù)據(jù)時(shí)用切片來表示后如何序列化成XML文本的搅吁;
代碼10?5的運(yùn)行結(jié)果是:
XML: <Students> ?
????<Student> ???
????????<Name>小明</Name> ???
????????<Age>11</Age> ???
????????<Gender>男</Gender> ?
????</Student> ?
????<Student> ???
????????<Gender>女</Gender> ???
????????<Name>小紅</Name> ???
????????<Age>9</Age> ?
????</Student>
</Students> ?
---分隔線---
students2T: &main.Students{Student:[]main.StringMap{main.StringMap{"Name":"小明", "Age":"11", "Gender":"男"}, main.StringMap{"Name":"小紅", "Age":"9", "Gender":"女"}}}
可以看出威创,對(duì)map[string]string類型的XML編解碼都被正確地應(yīng)用了,因此我們實(shí)現(xiàn)了Go語言中對(duì)map[string]string類型XML編解碼的支持谎懦。
從前面的這些實(shí)例來看肚豺,Go語言中處理XML序列化與反序列化,理論上結(jié)構(gòu)體中不加任何描述字符串也可以進(jìn)行序列化和反序列化界拦,加入描述字符串則可以較為精細(xì)地進(jìn)行序列化和反序列化吸申,至于更進(jìn)一步的自由控制XML的解析或輸出,需要應(yīng)用xml包中更多的函數(shù)甚至自行編寫處理函數(shù)來進(jìn)行享甸。最后一種方法由于其復(fù)雜性以及生成的XML代碼有可能兼容性不好截碴,除非不得已不太建議使用。