go语言中的xml和结构体相互转换 单元测试用例,演示了xml和struct的相互转换和xml文件读取,单元测试用例编写等技术。
xml和struct相互转换注意事项:
- 结构体字段的首字母必须大写;
- 每个结构体的字段都需要加tag,如: `xml:"serverName"`
- 自定义的结构体要和解析的xml的结构对应,否则无法解析数据。
- 对于xml的主节点结构体字段的类型是 xml.Name 如:XName xml.Name `xml:"servers"` 则在xml.Unmarshal解析后这个字段会有2个子字段Space和Local,如无特别希求,反序列化时可以省略,且在序列化时必须省略,否则会有一个空节点
xml和struct相互转换单元测试用例
// xml_test.go
package xmldemo
import (
"encoding/xml"
"fmt"
"io"
"os"
)
// xml外层结构体定义 xml的节点名称需要使用 xml.Name 类型来定义
type Servers struct {
Version int `xml:"version,attr"` // 这个获取的是 servers节点上面的属性 version的值
// Content string `xml:",innerxml"` // 这个获取内部XML的值 用不到,可忽略
Data []Server `xml:"server"` // 这里对应 <server> 节点,因为有多个,所有是一个切片
}
// xml内容节点结构体定义 注意结构体的字段名称首字母需要大写,否则无法获取值(因为xml内部使用的是反射读取tag而获取值)
type Server struct {
ServerName string `xml:"serverName"`
ServerIp string `xml:"serverIP"`
}
// 将自定义的struct结构体对象转换为xml字符串
// tekintian@gmail.com
func ExampleXmlMarshal() {
ss := Servers{Version: 1}
ss.Data = append(ss.Data, Server{ServerName: "云南数据中心", ServerIp: "192.168.8.1"})
ss.Data = append(ss.Data, Server{ServerName: "香港数据中心", ServerIp: "10.1.1.1"})
//buf, err := xml.Marshal(ss)
buf, err := xml.MarshalIndent(ss, " ", " ") //输出格式化后的xml
if err != nil {
fmt.Printf("error: %v\n", err)
}
// xml.Header为xml头信息,即: `<?xml version="1.0" encoding="UTF-8"?>`
xmlStr := fmt.Sprintf("%v%s", xml.Header, buf) // 拼接最终的xml字符串
fmt.Println(xmlStr)
//output:
// <?xml version="1.0" encoding="UTF-8"?>
// <Servers version="1">
// <server>
// <serverName>云南数据中心</serverName>
// <serverIP>192.168.8.1</serverIP>
// </server>
// <server>
// <serverName>香港数据中心</serverName>
// <serverIP>10.1.1.1</serverIP>
// </server>
// </Servers>
}
// 将xml数据转换为自定义的struct结构体对象示例
func ExampleXmlUnmarshal() {
xmldata, _ := readFile("servers.xml")
servers := Servers{}
err := xml.Unmarshal(xmldata, &servers)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Version: %v ", servers.Version) //输出xml版本 Version: 1
// 循环输出所有server
for _, v := range servers.Data {
fmt.Printf("ServerName:%v ServerIP:%v ", v.ServerName, v.ServerIp)
}
//output: Version: 1 ServerName:Shanghai_VPN ServerIP:127.0.0.1 ServerName:Beijing_VPN ServerIP:127.0.0.2
}
// 读取文件内容
func readFile(filename string) ([]byte, error) {
if file, err := os.Open(filename); err == nil {
defer file.Close()
return io.ReadAll(file)
} else {
panic(fmt.Errorf("读取文件失败: %v", err))
}
}
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>
</servers>