golang xml文件转struct结构体,结构体转xml字符串使用注意事项和单元测试用例

go语言中的xml和结构体相互转换 单元测试用例,演示了xml和struct的相互转换和xml文件读取,单元测试用例编写等技术。

xml和struct相互转换注意事项:

  1. 结构体字段的首字母必须大写;
  2. 每个结构体的字段都需要加tag,如:  `xml:"serverName"`
  3. 自定义的结构体要和解析的xml的结构对应,否则无法解析数据。
  4. 对于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>

数据内存结构图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值