Golang程序员go语言学习

Golang 学习笔记(09)—— json和xml解析

2018-01-03  本文已影响96人  ChainZhang

本文为转载,原文:Golang 学习笔记(09)—— json和xml解析

Golang

xml

package

import "encoding/xml"

函数

Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal函数返回v的XML编码。

Marshal处理数组或者切片时会序列化每一个元素。Marshal处理指针时,会序列化其指向的值;如果指针为nil,则啥也不输出。Marshal处理接口时,会序列化其内包含的具体类型值,如果接口值为nil,也是不输出。Marshal处理其余类型数据时,会输出一或多个包含数据的XML元

Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal解析XML编码的数据并将结果存入v指向的值。v只能指向结构体、切片或者和字符串。良好格式化的数据如果不能存入v,会被丢弃。

因为Unmarshal使用reflect包,它只能填写导出字段。本函数好似用大小写敏感的比较来匹配XML元素名和结构体的字段名/标签键名。

例子

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(){
    //实例化对象
    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创建一个写入w的*Encoder。

(*Encoder) Encode

func (enc *Encoder) Encode(v interface{}) error

Encode将v编码为XML后写入底层。

NewDecoder

func NewDecoder(r io.Reader) *Decoder

创建一个从r读取XML数据的解析器。如果r未实现io.ByteReader接口,NewDecoder会为其添加缓存。

(*Decoder) Decode

func (d *Decoder) Decode(v interface{}) error

Decode方法功能类似xml.Unmarshal函数,但会从底层读取XML数据并查找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()
    //实例化对象
    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对象
    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

返回输入流里的下一个XML token。在输入流的结尾处,会返回(nil, io.EOF)

返回的token数据里的[]byte数据引用自解析器内部的缓存,只在下一次调用Token之前有效。如要获取切片的拷贝,调用CopyToken函数或者token的Copy方法。

成功调用的Token方法会将自我闭合的元素(如
)扩展为分离的起始和结束标签。

Token方法会保证它返回的StartElement和EndElement两种token正确的嵌套和匹配:如果本方法遇到了不正确的结束标签,会返回一个错误。

我们看下面的例子

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()
    //实例化对象
    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解析是最快的。对于大文件解析,对于性能要求高时,这种方式是最好的选择

json

package

import "encoding/json"

函数

Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal函数返回v的json编码。

Marshal函数会递归的处理值。如果一个值实现了Marshaler接口切非nil指针,会调用其MarshalJSON方法来生成json编码。nil指针异常并不是严格必需的,但会模拟与UnmarshalJSON的行为类似的必需的异常。

否则,Marshal函数使用下面的基于类型的默认编码格式:

布尔类型编码为json布尔类型。

浮点数、整数和Number类型的值编码为json数字类型。

字符串编码为json字符串。角括号"<"和">"会转义为"\u003c"和"\u003e"以避免某些浏览器吧json输出错误理解为HTML。基于同样的原因,"&"转义为"\u0026"。

数组和切片类型的值编码为json数组,但[]byte编码为base64编码字符串,nil切片编码为null。

Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal函数解析json编码的数据并将结果存入v指向的值。

Unmarshal和Marshal做相反的操作,必要时申请映射、切片或指针,有如下的附加规则:

要将json数据解码写入一个指针,Unmarshal函数首先处理json数据是json字面值null的情况。此时,函数将指针设为nil;否则,函数将json数据解码写入指针指向的值;如果指针本身是nil,函数会先申请一个值并使指针指向它。

要将json数据解码写入一个结构体,函数会匹配输入对象的键和Marshal使用的键(结构体字段名或者它的标签指定的键名),优先选择精确的匹配,但也接受大小写不敏感的匹配。

要将json数据解码写入一个接口类型值,函数会将数据解码为如下类型写入接口:

Bool                   对应JSON布尔类型
float64                对应JSON数字类型
string                 对应JSON字符串类型
[]interface{}          对应JSON数组
map[string]interface{} 对应JSON对象
nil                    对应JSON的null

如果一个JSON值不匹配给出的目标类型,或者如果一个json数字写入目标类型时溢出,Unmarshal函数会跳过该字段并尽量完成其余的解码操作。如果没有出现更加严重的错误,本函数会返回一个描述第一个此类错误的详细信息的UnmarshalTypeError。

JSON的null值解码为go的接口、指针、切片时会将它们设为nil,因为null在json里一般表示“不存在”。 解码json的null值到其他go类型时,不会造成任何改变,也不会产生错误。

当解码字符串时,不合法的utf-8或utf-16代理(字符)对不视为错误,而是将非法字符替换为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(){
    //实例化对象
    stu := Student{23, Address{"shanghai","pudong"},[]Email{Email{"home","home@qq.com"}, Email{"work","work@qq.com"}},"chain","zhang"}
    fmt.Println("stu: ", stu)
    //序列化对象到字符串
    buf, err1 := json.Marshal(stu)
    if err1 != nil{
        fmt.Println("err1: ", err1.Error())
        return
    }
    fmt.Println("json: ", string(buf))
    //反序列化字符串到对象
    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创建一个将数据写入w的*Encoder。

(*Encoder) Encode

func (enc *Encoder) Encode(v interface{}) error

Encode将v的json编码写入输出流,并会写入一个换行符。

NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder创建一个从r读取并解码json对象的*Decoder,解码器有自己的缓冲,并可能超前读取部分json数据。

(*Decoder) Decode

func (dec *Decoder) Decode(v interface{}) error

Decode从输入流读取下一个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()
    //实例化对象
    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)
}
运行结果
文件保存内容

转载请注明出处:
Golang 学习笔记(09)—— json和xml解析

目录
上一节:Golang 学习笔记(08)—— 文件操作
下一节:Golang 学习笔记(10)—— mysql操作

上一篇下一篇

猜你喜欢

热点阅读