Golang 学习笔记(09)—— json和xml解析
本文为转载,原文:Golang 学习笔记(09)—— json和xml解析
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解析