本文為轉(zhuǎn)載枪眉,原文:Golang 學(xué)習(xí)筆記(09)—— json和xml解析
xml
package
import "encoding/xml"
函數(shù)
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元
Unmarshal
func Unmarshal(data []byte, v interface{}) error
Unmarshal解析XML編碼的數(shù)據(jù)并將結(jié)果存入v指向的值。v只能指向結(jié)構(gòu)體捏鱼、切片或者和字符串执庐。良好格式化的數(shù)據(jù)如果不能存入v,會(huì)被丟棄导梆。
因?yàn)閁nmarshal使用reflect包轨淌,它只能填寫導(dǎo)出字段。本函數(shù)好似用大小寫敏感的比較來匹配XML元素名和結(jié)構(gòu)體的字段名/標(biāo)簽鍵名看尼。
例子
package main
import (
"fmt"
"encoding/xml"
)
type Address struct{
City string
Area string
}
type Email struct{
Where string `xml:"where,attr"`
Addr string
}
type Student struct{
Id int `xml:"id,attr"`
Address
Email []Email
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
}
func main(){
//實(shí)例化對(duì)象
stu := Student{23, Address{"shanghai","pudong"},[]Email{Email{"home","home@qq.com"}, Email{"work","work@qq.com"}},"chain","zhang"}
fmt.Println("stu:", stu)
//序列化
buf,err := xml.Marshal(stu)
if err != nil{
fmt.Println(err.Error())
return
}
fmt.Println("xml: ", string(buf))
var newStu Student
//反序列化
err1 := xml.Unmarshal(buf, &newStu)
if err1 != nil{
fmt.Println(err1.Error())
return
}
fmt.Println("newStu: ", newStu)
}
NewEncoder
func NewEncoder(w io.Writer) *Encoder
NewEncoder創(chuàng)建一個(gè)寫入w的*Encoder递鹉。
(*Encoder) Encode
func (enc *Encoder) Encode(v interface{}) error
Encode將v編碼為XML后寫入底層。
NewDecoder
func NewDecoder(r io.Reader) *Decoder
創(chuàng)建一個(gè)從r讀取XML數(shù)據(jù)的解析器藏斩。如果r未實(shí)現(xiàn)io.ByteReader接口躏结,NewDecoder會(huì)為其添加緩存。
(*Decoder) Decode
func (d *Decoder) Decode(v interface{}) error
Decode方法功能類似xml.Unmarshal函數(shù)狰域,但會(huì)從底層讀取XML數(shù)據(jù)并查找StartElement媳拴。
示例
package main
import (
"os"
"fmt"
"encoding/xml"
)
type Address struct{
City string
Area string
}
type Email struct{
Where string `xml:"where,attr"`
Addr string
}
type Student struct{
Id int `xml:"id,attr"`
Address
Email []Email
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
}
func main(){
t2()
}
func t2(){
f, err := os.Create("d:/myxml.xml")
if err != nil{
fmt.Println("err: ", err.Error())
return
}
defer f.Close()
//實(shí)例化對(duì)象
stu := Student{23, Address{"shanghai","pudong"},[]Email{Email{"home","home@qq.com"}, Email{"work","work@qq.com"}},"chain","zhang"}
fmt.Println("stu: ", stu)
//序列化到文件中
encoder := xml.NewEncoder(f)
err1 := encoder.Encode(stu)
if err1 != nil{
fmt.Println("err1: ", err1.Error())
return
}
//重置文件指針
f.Seek(0, os.SEEK_SET)
var newStu Student
//反序列化到newStu對(duì)象
decoder := xml.NewDecoder(f)
err2 := decoder.Decode(&newStu)
if err2 != nil{
fmt.Println("err2: ", err2.Error())
return
}
fmt.Println("new stu: ", newStu)
}
Token
處了上面的方法,xml包還提供了其他的解析xml方法兆览。在.net屈溉,java中都提供了XMLReader類來解析xml,在go中也有類似的方法抬探。
(*Decoder) Token
func (d *Decoder) Token() (t Token, err error)Token
返回輸入流里的下一個(gè)XML token语婴。在輸入流的結(jié)尾處,會(huì)返回(nil, io.EOF)
返回的token數(shù)據(jù)里的[]byte數(shù)據(jù)引用自解析器內(nèi)部的緩存,只在下一次調(diào)用Token之前有效砰左。如要獲取切片的拷貝匿醒,調(diào)用CopyToken函數(shù)或者token的Copy方法。
成功調(diào)用的Token方法會(huì)將自我閉合的元素(如
)擴(kuò)展為分離的起始和結(jié)束標(biāo)簽缠导。
Token方法會(huì)保證它返回的StartElement和EndElement兩種token正確的嵌套和匹配:如果本方法遇到了不正確的結(jié)束標(biāo)簽廉羔,會(huì)返回一個(gè)錯(cuò)誤。
我們看下面的例子
package main
import (
"os"
"fmt"
"encoding/xml"
)
type Address struct{
City string
Area string
}
type Email struct{
Where string `xml:"where,attr"`
Addr string
}
type Student struct{
Id int `xml:"id,attr"`
Address
Email []Email
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
}
func main(){
XmlT3()
}
func XmlT3(){
f, err := os.Create("d:/myxml.xml")
if err != nil{
fmt.Println("err: ", err.Error())
return
}
defer f.Close()
//實(shí)例化對(duì)象
stu := Student{23, Address{"shanghai","pudong"},[]Email{Email{"home","home@qq.com"}, Email{"work","work@qq.com"}},"chain","zhang"}
fmt.Println("stu: ", stu)
//序列化到文件中
encoder := xml.NewEncoder(f)
err1 := encoder.Encode(stu)
if err1 != nil{
fmt.Println("err1: ", err1.Error())
return
}
//重置文件指針
f.Seek(0, os.SEEK_SET)
decoder := xml.NewDecoder(f)
var strName string
for{
token, err2 := decoder.Token()
if err2 != nil{
break
}
switch t := token.(type){
case xml.StartElement:
stelm := xml.StartElement(t)
fmt.Println("start: ", stelm.Name.Local)
strName = stelm.Name.Local
case xml.EndElement:
endelm := xml.EndElement(t)
fmt.Println("end: ", endelm.Name.Local)
case xml.CharData:
data := xml.CharData(t)
str := string(data)
switch strName{
case "City":
fmt.Println("city:", str)
case "first":
fmt.Println("first: ", str)
}
}
}
}
上面這幾種方法僻造,Token解析是最快的憋他。對(duì)于大文件解析,對(duì)于性能要求高時(shí)髓削,這種方式是最好的選擇
json
package
import "encoding/json"
函數(shù)
Marshal
func Marshal(v interface{}) ([]byte, error)
Marshal函數(shù)返回v的json編碼竹挡。
Marshal函數(shù)會(huì)遞歸的處理值。如果一個(gè)值實(shí)現(xiàn)了Marshaler接口切非nil指針立膛,會(huì)調(diào)用其MarshalJSON方法來生成json編碼揪罕。nil指針異常并不是嚴(yán)格必需的,但會(huì)模擬與UnmarshalJSON的行為類似的必需的異常宝泵。
否則好啰,Marshal函數(shù)使用下面的基于類型的默認(rèn)編碼格式:
布爾類型編碼為json布爾類型。
浮點(diǎn)數(shù)儿奶、整數(shù)和Number類型的值編碼為json數(shù)字類型框往。
字符串編碼為json字符串。角括號(hào)"<"和">"會(huì)轉(zhuǎn)義為"\u003c"和"\u003e"以避免某些瀏覽器吧json輸出錯(cuò)誤理解為HTML闯捎∫祝基于同樣的原因,"&"轉(zhuǎn)義為"\u0026"瓤鼻。
數(shù)組和切片類型的值編碼為json數(shù)組男应,但[]byte編碼為base64編碼字符串,nil切片編碼為null娱仔。
Unmarshal
func Unmarshal(data []byte, v interface{}) error
Unmarshal函數(shù)解析json編碼的數(shù)據(jù)并將結(jié)果存入v指向的值。
Unmarshal和Marshal做相反的操作游桩,必要時(shí)申請(qǐng)映射牲迫、切片或指針,有如下的附加規(guī)則:
要將json數(shù)據(jù)解碼寫入一個(gè)指針借卧,Unmarshal函數(shù)首先處理json數(shù)據(jù)是json字面值null的情況盹憎。此時(shí),函數(shù)將指針設(shè)為nil铐刘;否則陪每,函數(shù)將json數(shù)據(jù)解碼寫入指針指向的值;如果指針本身是nil,函數(shù)會(huì)先申請(qǐng)一個(gè)值并使指針指向它檩禾。
要將json數(shù)據(jù)解碼寫入一個(gè)結(jié)構(gòu)體挂签,函數(shù)會(huì)匹配輸入對(duì)象的鍵和Marshal使用的鍵(結(jié)構(gòu)體字段名或者它的標(biāo)簽指定的鍵名),優(yōu)先選擇精確的匹配盼产,但也接受大小寫不敏感的匹配饵婆。
要將json數(shù)據(jù)解碼寫入一個(gè)接口類型值,函數(shù)會(huì)將數(shù)據(jù)解碼為如下類型寫入接口:
Bool 對(duì)應(yīng)JSON布爾類型
float64 對(duì)應(yīng)JSON數(shù)字類型
string 對(duì)應(yīng)JSON字符串類型
[]interface{} 對(duì)應(yīng)JSON數(shù)組
map[string]interface{} 對(duì)應(yīng)JSON對(duì)象
nil 對(duì)應(yīng)JSON的null
如果一個(gè)JSON值不匹配給出的目標(biāo)類型戏售,或者如果一個(gè)json數(shù)字寫入目標(biāo)類型時(shí)溢出侨核,Unmarshal函數(shù)會(huì)跳過該字段并盡量完成其余的解碼操作。如果沒有出現(xiàn)更加嚴(yán)重的錯(cuò)誤灌灾,本函數(shù)會(huì)返回一個(gè)描述第一個(gè)此類錯(cuò)誤的詳細(xì)信息的UnmarshalTypeError搓译。
JSON的null值解碼為go的接口、指針锋喜、切片時(shí)會(huì)將它們?cè)O(shè)為nil些己,因?yàn)閚ull在json里一般表示“不存在”。 解碼json的null值到其他go類型時(shí)跑芳,不會(huì)造成任何改變轴总,也不會(huì)產(chǎn)生錯(cuò)誤。
當(dāng)解碼字符串時(shí)博个,不合法的utf-8或utf-16代理(字符)對(duì)不視為錯(cuò)誤怀樟,而是將非法字符替換為unicode字符U+FFFD。
例子
package main
import (
"os"
"fmt"
"encoding/json"
)
type Address struct{
City string `json:"ciry"`
Area string `json:"area"`
}
type Email struct{
Where string `json:"where"`
Addr string `json:"addr"`
}
type Student struct{
Id int `json:"id"`
Address `json:"address"`
Emails []Email `json:"emails"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
func main(){
JsonT1()
}
func JsonT1(){
//實(shí)例化對(duì)象
stu := Student{23, Address{"shanghai","pudong"},[]Email{Email{"home","home@qq.com"}, Email{"work","work@qq.com"}},"chain","zhang"}
fmt.Println("stu: ", stu)
//序列化對(duì)象到字符串
buf, err1 := json.Marshal(stu)
if err1 != nil{
fmt.Println("err1: ", err1.Error())
return
}
fmt.Println("json: ", string(buf))
//反序列化字符串到對(duì)象
var newStu Student
err2 := json.Unmarshal(buf, &newStu)
if err2 != nil{
fmt.Println("err2: ", err2.Error())
return
}
fmt.Println("new stu: ", newStu)
}
NewEncoder
func NewEncoder(w io.Writer) *Encoder
NewEncoder創(chuàng)建一個(gè)將數(shù)據(jù)寫入w的*Encoder盆佣。
(*Encoder) Encode
func (enc *Encoder) Encode(v interface{}) error
Encode將v的json編碼寫入輸出流往堡,并會(huì)寫入一個(gè)換行符。
NewDecoder
func NewDecoder(r io.Reader) *Decoder
NewDecoder創(chuàng)建一個(gè)從r讀取并解碼json對(duì)象的*Decoder共耍,解碼器有自己的緩沖虑灰,并可能超前讀取部分json數(shù)據(jù)。
(*Decoder) Decode
func (dec *Decoder) Decode(v interface{}) error
Decode從輸入流讀取下一個(gè)json編碼值并保存在v指向的值里痹兜。
例子
package main
import (
"os"
"fmt"
"encoding/json"
)
type Address struct{
City string `json:"ciry"`
Area string `json:"area"`
}
type Email struct{
Where string `json:"where"`
Addr string `json:"addr"`
}
type Student struct{
Id int `json:"id"`
Address `json:"address"`
Emails []Email `json:"emails"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
func main(){
JsonT2()
}
func JsonT2(){
f, err1 := os.Create("d:/myjson.txt")
if err1 != nil{
fmt.Println("err1: ", err1.Error())
return
}
defer f.Close()
//實(shí)例化對(duì)象
stu := Student{23, Address{"shanghai","pudong"},[]Email{Email{"home","home@qq.com"}, Email{"work","work@qq.com"}},"chain","zhang"}
fmt.Println("stu: ", stu)
//序列化
encoder := json.NewEncoder(f)
err2 := encoder.Encode(stu)
if err2 != nil{
fmt.Println("err2: ", err2.Error)
return
}
//重置文件指針
f.Seek(0, os.SEEK_SET)
var newStu Student
//反序列化
decoder := json.NewDecoder(f)
err3 := decoder.Decode(&newStu)
if err3 != nil{
fmt.Println("err3: ", err3.Error())
return
}
fmt.Println("new stu: ", newStu)
}
完
轉(zhuǎn)載請(qǐng)注明出處:
Golang 學(xué)習(xí)筆記(09)—— json和xml解析
目錄
上一節(jié):Golang 學(xué)習(xí)筆記(08)—— 文件操作
下一節(jié):Golang 學(xué)習(xí)筆記(10)—— mysql操作