go 操作xml 和 json 分别使用 encoding/xml 和 encoding/json 来实现 下面我们通过代码来讲解一下go 操作xml 文件 和 json 格式数据
读取xml
假设我有一个xml 文件如下
C:\\Users\\admin\\go\\src\\html\\mgr.xml
<?xml version="1.0" encoding="utf-8"?>
<servers version="1">
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
<database>
<databaseName>Oracle</databaseName>
<databasePort>1521</databasePort>
</database>
<database>
<databaseName>MySQL</databaseName>
<databasePort>3306</databasePort>
</database>
</servers>
现在我们需要取出其中的数据 我们需要定义结构体 定义我们需要拿到xml的哪些标签,例如我现在想拿到server 标签和 database 标签里面的数据那我就需要为这两个标签分别定义两个结构体
为元素定义结构体
// server 标签
type servers struct {
XMLName xml.Name `xml:"server"`
ServerName string `xml:"serverName"`
ServerIP string `xml:"serverIP"`
}
// database 标签
type database struct {
XMLName xml.Name `xml:"database"`
DatabaseName string `xml:"databaseName"`
DatabasePort int `xml:"databasePort"`
}
// 整个xml 文件 里面包含了 server 和 database 标签
type XmlData struct {
XmlName xml.Name `xml:"servers"`
Version string `xml:"version,attr"`
Servers []servers `xml:"server"`
Database []database `xml:"database"`
Desc string `xml:",innerxml"`
}
这里需要注意几点1. 结构体的字段必须是可导出的 2.tag 必须和xml 里面的元素名称一样,也就是 xml:"xx" 这个地方 定义的tag 和 xml 元素名称不一样或者说大小写不一样都会导致xml 元素解析不出来,例如我的xml:"databasePort" 这个databasePort 必须和 xml 里面的标签一样的名称
完整代码demo
package growth
// 学习go 第十四天 学习使用go io操作
import (
"fmt"
"os"
"io/ioutil"
"path/filepath"
"encoding/xml"
)
func Day14IO() {
currentPath, _ := filepath.Abs(os.Args[0])
fmt.Println(currentPath)
// 打开并读取文件
data, err:= ioutil.ReadFile("C:\\Users\\admin\\go\\情绪.jpg")
if err != nil {
fmt.Println(err)
}
fmt.Println(string(data))
}
func Day14Xml() {
// 学习使用go 处理xml, go 使用xml.Unmarshal(data []byte, v interface{}) error 来处理xml文件
/*
我们需要定义结构体来获取我们需要解析的xml标签
Unmarshal解析的时候XML元素和struct字段怎么对应起来的呢?
这是有一个优先级读取流程的,首先会读取struct tag,也就是 `xml:"xx"` 这个地方
如果没有,那么就会对应字段名。必须注意一点的是解析的时候tag、
字段名、XML元素都是大小写敏感的,所以必须一一对应字段
解析XML到struct的时候遵循如下的规则:
1. 如果struct的一个字段是string或者[]byte类型且它的tag
含有",innerxml",Unmarshal将会将此字段所对应的元素内所有内嵌的原始xml
累加到此字段上,如上面例子Description定义。最后的输出是
2. 如果struct中有一个叫做XMLName,且类型为xml.Name字段,
那么在解析的时候就会保存这个element的名字到该字段,如上面例子中的servers。
3. 如果某个struct字段的tag定义中含有XML结构中element的名称,
那么解析的时候就会把相应的element值赋值给该字段,
如上servername和serverip定义
4. 如果某个struct字段的tag定义了中含有",attr",
那么解析的时候就会将该结构所对应的element的与字段同名的
属性的值赋值给该字段,如上version定义
5. 如果某个struct字段的tag定义了"-",那么不会为该字段解析匹配任何xml数据
6. 如果struct字段后面的tag定义了",any",如果他的子元素在不满足其他的规则的时候就会匹配到这个字段
*/
type servers struct {
XMLName xml.Name `xml:"server"`
ServerName string `xml:"serverName"`
ServerIP string `xml:"serverIP"`
}
type database struct {
XMLName xml.Name `xml:"database"`
DatabaseName string `xml:"databaseName"`
DatabasePort int `xml:"databasePort"`
}
type XmlData struct {
XmlName xml.Name `xml:"servers"`
Version string `xml:"version,attr"`
Servers []servers `xml:"server"`
Database []database `xml:"database"`
Desc string `xml:",innerxml"`
}
filename := "C:\\Users\\admin\\go\\src\\html\\mgr.xml"
file , err := os.Open(filename)
if err != nil {
fmt.Println("Open File err", err)
return
}
defer file.Close()
// 读取xml 文件
data, e1 := ioutil.ReadAll(file)
if e1 != nil {
fmt.Println("Read File Err", err)
return
}
properties := &XmlData{}
// 通过xml.Umarshal 解析xml
e2 := xml.Unmarshal(data, properties)
if e2 != nil {
fmt.Println(e2)
return
}
fmt.Println(properties.Servers[0].ServerIP)
fmt.Println(properties.Servers[0].ServerName)
fmt.Println(properties.Database[0].DatabaseName)
fmt.Println(properties.Database[0].DatabasePort)
fmt.Println(properties.Database[1].DatabaseName)
fmt.Println(properties.Database[1].DatabasePort)
}
读取json
现在假如我们有这样一个json 数据
{"ip": "192.168.1.100", "port": 1521, "nums": [1, 2, 3], "relation": {"mykey": "myval"}}
我们想拿到里面全部的key-value
go 解析json 同样需要定义结构体
为这个json 定义结构体
type data struct {
// 结构体里面的字段必须是可导出的(大写字母开头)
// 且字段名要和json 里面key的名称一样
Ip string
Port int
Nums []int
Relation map[string]string
}
然后使用 json.Unmarshal来解析
完整的代码demo
package growth
// 学习go 第十六天 学习使用go 操作json
import (
"fmt"
"encoding/json"
)
type data struct {
// 结构体里面的字段必须是可导出的(大写字母开头)
// 且字段名要和json 里面key的名称一样
Ip string
Port int
Nums []int
Relation map[string]string
}
func Day16Json() {
/*
在解析的时候,如何将json数据与struct字段相匹配呢?
例如JSON的key是Foo,那么怎么找对应的字段呢?
首先查找tag含有Foo的可导出的struct字段(首字母大写)
其次查找字段名是Foo的导出字段
最后查找类似FOO或者FoO这样的除了首字母之外其他大小写不敏感的
导出字段
*/
var loads data
js := []byte(`{"ip": "192.168.1.100", "port": 1521, "nums": [1, 2, 3], "relation": {"mykey": "myval"}}`)
// 解析json
err := json.Unmarshal(js, &loads)
if err != nil {
fmt.Println("Unmarshal Err", err)
return
}
fmt.Println(loads)
// 生成json, 假如我们需要生成像上面一样的json 需要通过json.Marshal 方法, 我们需要Marshal的对象还是结构体
var dumps data
dumps.Ip = "127.0.0.1"
dumps.Port = 3306
dumps.Nums = []int {1, 2, 3}
dumps.Relation = map[string]string{"key": "value"}
// Marshal 之后返回的是byte 类型的数组[]byte
dump, e2 := json.Marshal(dumps)
if e2 != nil {
fmt.Println("Marshal Err", e2)
return
}
// dump 是 byte 类型的数组
fmt.Println(dump)
// 转换为string就可以看到json
fmt.Println(string(dump))
}
json 数据写入文件
将json 写入文件需要使用 NewEncoder 函数,创建一个文件,然后将结构体数据 Encode 到文件中
type ServerData struct {
Ip string `json:"ip"`
Port int `json:"port"`
ServerList []string `json:"serverList"`
}
type Server struct {
Data ServerData `json:"data"`
Code int `json:"code"`
}
// json 写入文件
func Json2File() {
fd, err := os.Create("data.json")
defer fd.Close()
if err != nil {
fmt.Println("create json fail")
return
}
var server Server
server.Code = 0
server.Data.Ip = "192.168.30.151"
server.Data.Port = 1521
server.Data.ServerList = []string{"nginx", "mysql"}
encoder := json.NewEncoder(fd)
err2 := encoder.Encode(server)
if err2 != nil {
fmt.Println("encode failed")
}
}
从文件中加载json数据
从文件中加载json 需要使用 NewDecoder 然后使用Decode函数decode 到结构体里面
type ServerData struct {
Ip string `json:"ip"`
Port int `json:"port"`
ServerList []string `json:"serverList"`
}
type Server struct {
Data ServerData `json:"data"`
Code int `json:"code"`
}
// 从文件中读取出json, 解析到结构体
func File2Json() {
var server Server
fd, _ := os.Open("data.json")
defer fd.Close()
decoder := json.NewDecoder(fd)
err := decoder.Decode(&server)
if err != nil {
fmt.Println("decode fail", err)
} else {
fmt.Println("decode data", server)
}
}