GolangGo 语言 XML 的序列与反序列化实践
Posted Fxtack
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GolangGo 语言 XML 的序列与反序列化实践相关的知识,希望对你有一定的参考价值。
Go 语言 XML 的序列与反序列化实践
导读
本文使用 Go 原生支持的包,对 XML 字符串以及 .xml
文件进行序列化与反序列化实践。同时对 Go 语言下的 JSON 序列化反序列化与 XML 的序列化反序列化进行性能测试与比对。
-
使用到的包是
encoding/xml
。详细文档可查看官方中文文档,链接为: https://studygolang.com/pkgdoc -
Go 语言 JSON 的序列与反序列化博客已经更新:
【Golang】Go 语言 JSON 的序列化与反序列化实践 -
请留意代码块中的注释,注释中有表示出一些非常重要的细节!
-
本文对 XML 的序列化与反序列化使用较基础,尚未对 XML 文件的标签属性等进行解析。若读者有需要,本文起到抛砖引玉的作用,详细的使用参见官方文档。
文章目录
一. 案例提出
我们以图书馆为原型进行建模。对于一个图书馆用 library.xml
文件进行描述。
<?xml version="1.0"?>
<Library>
<name>China library</name>
<location>China</location>
<isPrivate>false</isPrivate>
<score>4.6</score>
<date>
<open>2020-07-31T14:27:10.035542+08:00</open>
<close>2020-07-31T14:27:10.035542+08:00</close>
</date>
<bookInfo>
<number>1005</number>
<book>
<name>Go 语言 JSON 序列化与反序列化</name>
<author>fxtack</author>
<publishTime>2021-07-08T17:44:53.199855+08:00</publishTime>
</book>
<book>
<name>Go 语言 XML 序列化与反序列化</name>
<author>fxtack</author>
<publishTime>2021-07-08T17:44:53.199855+08:00</publishTime>
</book>
</bookInfo>
</Library>
下表对字段进行解释
字段名 | 类型 | 映射 Go 类型 | 解释 |
---|---|---|---|
library | - | Library(自定义结构体) | 图书馆根标签 |
name | 字符串 | string | 图书馆名 |
location | 字符串 | string | 所在地 |
isPrivate | 布尔 | bool | 是否是私有图书馆 |
score | 浮点数 | float64 | 点评星级 |
date | - | Date(自定义结构体) | 图书馆开馆闭馆 |
open | 字符串 | time.Time | 开馆时间 |
close | 字符串 | time.Time | 必馆时间 |
bookInfo | - | BookInfo(自定义结构体) | 图书信息 |
number | 整型 | int | 图书总数 |
book | - | Book(自定义结构体) | 图书 |
(book) name | 字符串 | string | 书名 |
(book) author | 字符串 | string | 作者 |
(book) publishTime | 字符串 | time.Time | 发布时间 |
Go 语言的结构体设计如下:
(其中 library.xml
文件中的标签字段名与 Go 结构体字段中的 xml 标签值一一对应)
package main
type Library struct {
Name string `xml:"name"`
Location string `xml:"location"`
IsPrivate bool `xml:"isPrivate"`
Score float64 `xml:"score"`
Date Date `xml:"date"`
BookInfo BookInfo `xml:"bookInfo"`
}
type Date struct {
Open time.Time `xml:"open"`
Close time.Time `xml:"close"`
}
type BookInfo struct {
Number int `xml:"number"`
BookList []Book `xml:"book"`
}
type Book struct {
Name string `xml:"name"`
Author string `xml:"author"`
PublishTime time.Time `xml:"publishTime"`
}
基于上述案例与模型进行序列化与反序列化。
一. XML 的序列化
1. 序列化的简单示例
在进行序列化对象为 .xml
文件之前,我们先创建一个 library 对象。
package main
import "time"
var library = Library{
Name: "一个图书馆",
Location: "中国",
IsPrivate: true,
Score: 4.9,
Date: Date{
Open: time.Now(),
Close: time.Now(),
},
BookInfo: BookInfo{
Number: 1005,
BookList: []Book{
{
Name: "Go 语言 JSON 序列化与反序列化",
Author: "fxtack",
PublishTime: time.Now(),
},
{
Name: "Go 语言 XML 序列化与反序列化",
Author: "fxtack",
PublishTime: time.Now(),
},
},
},
}
通过序列化我们可以将该对象变为一个 XML 字符串,并简单的打印输出:
package main
import (
"encoding/xml"
"fmt"
"log"
)
func main(){
// 序列化同在 main 包下的 library
result, err := xml.Marshal(&library)
if err != nil {
log.Println("对象序列化为 XML 字符串失败")
}
// result 是字节切片类型,要转为字符串再输出
fmt.Println(string(result))
}
输出结果如下。
<Library><name>广东大图书馆</name><location>广东</location><isPrivate>false</isPrivate><score>4.6</score><date><open>2021-07-08T18:26:33.7720883+08:00</open><close>2021-07-08T18:26:33.7720883+08:00</close></date><bookInfo><number>1005</number><book><name>Go 语言 JSON 序列化与反序列化</name><author>fxtack</author><publishTime>2021-07-08T18:26:33.7720883+08:00</publishTime></book><book><name>Go 语言 XML 序列化与反序列化</name><author>fxtack</author><publishTime>2021-07-08T18:26:33.7720883+08:00</publishTime></book></bookInfo></Library>
很明显这个输出结果的格式太难看了,很长一条。Go 也有考虑到这个问题,因此我们可以使用 xml.MarshalIndent
方法来解决格式化输出的问题。
package main
import (
"encoding/xml"
"fmt"
"log"
)
func main(){
// 使用了 xml.MarshalIndent 来进行格式序列化
// 第二个参数为 xml 每行的前缀
// 第三个参数为标签嵌套时使用的空位符,这里选择用缩进值,也可以使用四个空格
result, err := xml.MarshalIndent(&library, "", "\\t")
if err != nil {
log.Println("对象序列化为 XML 字符串失败")
}
fmt.Println(string(result))
}
此时的输出就非常规范易读了。
<Library>
<name>广东大图书馆</name>
<location>广东</location>
<isPrivate>false</isPrivate>
<score>4.6</score>
<date>
<open>2021-07-08T18:34:52.9834418+08:00</open>
<close>2021-07-08T18:34:52.9834418+08:00</close>
</date>
<bookInfo>
<number>1005</number>
<book>
<name>Go 语言 JSON 序列化与反序列化</name>
<author>fxtack</author>
<publishTime>2021-07-08T18:34:52.9834418+08:00</publishTime>
</book>
<book>
<name>Go 语言 XML 序列化与反序列化</name>
<author>fxtack</author>
<publishTime>2021-07-08T18:34:52.9834418+08:00</publishTime>
</book>
</bookInfo>
</Library>
注意
无论是
xml.Marshal
还是xml.MarshalIndent
方法,其传入的第一个参数值类型是interface{}
类型,也就是用于进行序列化的对象。传入的可以是对象,也可以是对象的地址,以下代码的效果是相同的(以xml.Marshal
为例),但是建议传入地址。... result, err := xml.Marshal(library) ...
... result, err := xml.Marshal(&library) ...
2. 序列化的完整代码
完整的序列化过程需要对象序列化后输出为 .xml
文件。其流程如下:
其中,有一个重要的细节,.xml
文件开头有一个头: <?xml version="1.0"?>
。这个头在序列化的结果中是没有的,所以得自己写入。
以下为完整代码:
package main
import (
"encoding/xml"
"log"
"os"
)
// library 对象同在 main 包下,详情见上文
func main() {
// 输出为当前项目目录下的 library.xml
WriteXML("./library.xml", &library)
}
func WriteXML(filePath string, ref interface{}) {
// 序列化
data, err := xml.MarshalIndent(ref, "", "\\t")
if err != nil {
log.Println("文件序列化错误")
}
// 拼接 xml 文件头到 xml 字符串前
data = append([]byte("<?xml version=\\"1.0\\"?>\\n"), data ...)
// 写出文件
err = os.WriteFile(filePath, data, 0666)
if err != nil {
log.Println("文件写入错误")
}
}
测试运行后在项目目录下出现 library.xml
并查看,发现 XML 的头也接上了,内容也没有问题。
二. XML 的反序列化
1. 反序列化的简单示例
以上文简单序列化过程中得到的字符串来进行反序列化测试。代码如下:
package main
import (
"encoding/xml"
"fmt"
"log"
)
func main() {
// 准备接受反序列化的空对象
var library Library
// 反序列化的 xml 字符串
xmlStr := "<?xml version=\\"1.0\\"?><Library><name>广东大图书馆</name><location>广东</location>" +
"<isPrivate>false</isPrivate><score>4.6</score><date>" +
"<open>2021-07-08T18:26:33.7720883+08:00</open>" +
"<close>2021-07-08T18:26:33.7720883+08:00</close></date>" +
"<bookInfo><number>1005</number><book><name>Go 语言 JSON 序列化与反序列化</name>" +
"<author>fxtack</author><publishTime>2021-07-08T18:26:33.7720883+08:00</publishTime>" +
"</book><book><name>Go 语言 XML 序列化与反序列化</name><author>fxtack</author><publishTime>" +
"2021-07-08T18:26:33.7720883+08:00</publishTime></book></bookInfo></Library>"
// 反序列化
err := xml.Unmarshal([]byte(xmlStr), &library)
if err != nil {
log.Println("反序列化失败")
}
fmt.Println(library)
}
输出如下,可见反序列化成功。
{广东大图书馆 广东 false 4.6 {2021-07-08 18:26:33.7720883 +0800 CST 2021-07-08 18:26:33.7720883 +0800 CST} {1005 [{Go 语言 JSON 序列化与反序列化 fxtack 2021-07-08 18:26:33.7720883 +0800 CST} {Go 语言 XML 序列化与反序列化 fxtack 2021-07-08 18:26:33.7720883 +0800 CST}]}}
注意
反序列化的函数
xml.Unmarshal
和序列化的函数不同,其传入的第二个参数必须是用于接受结果的结构体对象的地址。即,如下代码第一段是正确的,第二段是错误的。... // 正确 err := xml.Unmarshal([]byte(xmlStr), &library) ...
... // 错误,会产生 err err := xml.Unmarshal([]byte(xmlStr), library) ...
2. 反序列化的完整代码
反序列化的完整代码要读取 .xml
文件,将读取的内容进行反序列化,得到一个对象。流程如下: