添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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 ( "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(){

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

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 ( "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 ( "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)

文件保存内容

作者:ChainZhang 链接:https://www.jianshu.com/p/283eee583339 來源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

🏁Eric