Golang 學(xué)習(xí)筆記(09)—— json和xml解析

本文為轉(zhuǎn)載枪眉,原文:Golang 學(xué)習(xí)筆記(09)—— json和xml解析

Golang

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)
}
運(yùn)行結(jié)果

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)
}
運(yùn)行結(jié)果

文件內(nèi)容

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)
            }
        }
    }
}
運(yùn)行結(jié)果

上面這幾種方法僻造,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)
}
運(yùn)行結(jié)果

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)
}
運(yùn)行結(jié)果

文件保存內(nèi)容

轉(zhuǎn)載請(qǐng)注明出處:
Golang 學(xué)習(xí)筆記(09)—— json和xml解析

目錄
上一節(jié):Golang 學(xué)習(xí)筆記(08)—— 文件操作
下一節(jié):Golang 學(xué)習(xí)筆記(10)—— mysql操作

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末穆咐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子字旭,更是在濱河造成了極大的恐慌对湃,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遗淳,死亡現(xiàn)場離奇詭異拍柒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)屈暗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門拆讯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脂男,“玉大人,你說我怎么就攤上這事种呐≡壮幔” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵陕贮,是天一觀的道長堕油。 經(jīng)常有香客問我,道長肮之,這世上最難降的妖魔是什么掉缺? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮戈擒,結(jié)果婚禮上眶明,老公的妹妹穿的比我還像新娘。我一直安慰自己筐高,他們只是感情好搜囱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柑土,像睡著了一般蜀肘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上稽屏,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天扮宠,我揣著相機(jī)與錄音,去河邊找鬼狐榔。 笑死坛增,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的薄腻。 我是一名探鬼主播收捣,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼庵楷!你這毒婦竟也來了罢艾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤尽纽,失蹤者是張志新(化名)和其女友劉穎咐蚯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜓斧,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年睁冬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挎春。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片看疙。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖直奋,靈堂內(nèi)的尸體忽然破棺而出能庆,到底是詐尸還是另有隱情,我是刑警寧澤脚线,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布搁胆,位于F島的核電站,受9級(jí)特大地震影響邮绿,放射性物質(zhì)發(fā)生泄漏渠旁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一船逮、第九天 我趴在偏房一處隱蔽的房頂上張望顾腊。 院中可真熱鬧,春花似錦挖胃、人聲如沸杂靶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吗垮。三九已至,卻和暖如春凹髓,著一層夾襖步出監(jiān)牢的瞬間烁登,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工扁誓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留防泵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓蝗敢,卻偏偏與公主長得像捷泞,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寿谴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354