Go实现对XML的读取和修改
前言
很久没有更新了,来水篇文章。这篇文章给大家介绍一下如何用Go来读取XML和修改XML。XML我就不多介绍了,相信大家都使用过,不了解的可以看下百度百科。
处理XML我们暂时不需要借助第三方库,使用Go标准库encoding包下的xml即可完成,"encoding/xml"。
读取XML
首先我们需要创建一个XML文件,模拟一个web平台的信息,需要协议、IP、端口号、用户名和密码、页面路径等信息。命名为
web.xml
.
xml
<?xml version="1.0" encoding="UTF-8"?>
<Web>
<Protocol>https</Protocol>
<Host>192.168.100.169</Host>
<Port>8080</Port>
<Account>
<Username>admin</Username>
<Password>123456</Password>
</Account>
<Link>
<Login>/api/login</Login>
<Index>/api/index/page</Index>
<Setting>/api/self/setting</Setting>
</Link>
</Web>
紧接着根据这个XML文件来编写对应的结构体树,需要注意的是我们需要在最上层的结构体中使用xml.Name字段来声明最外围标签的名称。
go
type WebContent struct {
XML xml.Name `json:"Web" xml:"Web"`
Protocol string `json:"protocol"`
Host string `json:"host"`
Port string `json:"port"`
Account *Account `json:"account"`
Link *Link `json:"link"`
}
type Account struct {
Username string `json:"username"`
Password string `json:"password"`
}
type Link struct {
Login string `json:"login"`
Index string `json:"index"`
Setting string `json:"setting"`
}
声明号XML文件对应的结构体之后,我们对文件进行解析读取。首先读取整个文件,获取到文件的字节数组,再通过xml包提供的Unmarshal方法进行反序列化。
由于是示例代码,错误都没有进行处理,选择直接panic。需要注意的是文件路径的问题,如果提示找不到文件,可以使用文件的绝对路径,或者使用os.Getwd()获取程序运行的当前目录,再将文件拷贝到当前目录中。以下是完整示例代码。
go
package main
import (
"encoding/xml"
"fmt"
"log"
"os"
)
// 这里我使用的是绝对路径
const (
XMLFilePath = "/Users/mac/Library/Application Support/JetBrains/GoLand2023.3/scratches/web.xml"
)
type WebContent struct {
XMLName xml.Name `json:"Web" xml:"Web"`
Protocol string `json:"protocol"`
Host string `json:"host"`
Port string `json:"port"`
Account *Account `json:"account"`
Link *Link `json:"link"`
}
type Account struct {
Username string `json:"username"`
Password string `json:"password"`
}
type Link struct {
Login string `json:"login"`
Index string `json:"index"`
Setting string `json:"setting"`
}
func main() {
readXMl()
}
func readXMl() {
data, err := os.ReadFile(XMLFilePath)
if err != nil {
log.Fatalf("读取文件%v失败: %v\n", XMLFilePath, err)
}
w := new(WebContent)
if err = xml.Unmarshal(data, &w); err != nil {
log.Fatal("XML数据解析失败", err)
}
fmt.Println("------------------------------")
fmt.Printf("Protocol: %v\nHost: %v\nPort: %v\nAccount:\n --Username: %v\n --Password: %v\nLink:\n --Login: %v\n --Index: %v\n --Setting: %v\n",
w.Protocol, w.Host, w.Port, w.Account.Username, w.Account.Password, w.Link.Login, w.Link.Index,w.Link.Setting)
fmt.Println("------------------------------")
}
/* 输出信息:
------------------------------
Protocol: http
Host: 192.168.100.169
Port: 80
Account:
--Username: sysadmin
--Password: sysadmin
Link:
--Login: /api/login
--Index: /api/index/page
--Setting: /api/self/setting
------------------------------
*/
修改XML
修改XML文件中的某几个字段,首先需要使用os.Open方法打开文件,拿到实现了i o.Reader接口的文件流,然后调用Decode方法反序列化数据。
使用赋值方法修改数据,完成后通过xml.MarshalIndent方法来序列化XML数据,并控制前缀和缩进。
最后再覆写文件,完成修改操作。以下是示例代码。
go
func amendXML() {
file, err := os.Open(XMLFilePath)
if err != nil {
log.Fatalf("打开文件%v失败: %v\n", XMLFilePath, err)
}
// 解析文件
w := new(WebContent)
if err = xml.NewDecoder(file).Decode(&w); err != nil {
log.Fatal("解析文件失败:", err)
}
// 修改数据
w.Protocol= "http"
w.Account.Password = "123456"
// 序列化XML数据,MarshalIndent后两个参数用来控制前缀和缩进
xmlData, err := xml.MarshalIndent(w, "", " ")
if err != nil {
log.Fatal(err)
}
// 覆写文件
xmlData = append([]byte(xml.Header), xmlData...)
if err = os.WriteFile(XMLFilePath, xmlData, 0777); err != nil {
log.Fatal("覆写文件失败:",err)
}
}
完整代码
以下是完整的代码,复制粘贴后,添加一个xml文件,修改文件路径后可直接运行
go
package main
import (
"encoding/xml"
"fmt"
"log"
"os"
)
const (
XMLFilePath = "/Users/mac/Library/Application Support/JetBrains/GoLand2023.3/scratches/web.xml"
)
type WebContent struct {
XMLName xml.Name `json:"Web" xml:"Web"`
Protocol string `json:"protocol"`
Host string `json:"host"`
Port string `json:"port"`
Account *Account `json:"account"`
Link *Link `json:"link"`
}
type Account struct {
Username string `json:"username"`
Password string `json:"password"`
}
type Link struct {
Login string `json:"login"`
Index string `json:"index"`
Setting string `json:"setting"`
}
func main() {
readXML()
amendXML()
readXML()
}
func readXML() {
data, err := os.ReadFile(XMLFilePath)
if err != nil {
log.Fatalf("读取文件%v失败: %v\n", XMLFilePath, err)
}
w := new(WebContent)
if err = xml.Unmarshal(data, &w); err != nil {
log.Fatal("XML数据解析失败", err)
}
fmt.Println("------------------------------")
fmt.Printf("Protocol: %v\nHost: %v\nPort: %v\nAccount:\n --Username: %v\n --Password: %v\nLink:\n --Login: %v\n --Index: %v\n --Setting: %v\n",
w.Protocol, w.Host, w.Port, w.Account.Username, w.Account.Password, w.Link.Login, w.Link.Index,w.Link.Setting)
fmt.Println("------------------------------")
}
func amendXML() {
file, err := os.Open(XMLFilePath)
if err != nil {
log.Fatalf("打开文件%v失败: %v\n", XMLFilePath, err)
}
// 解析文件
w := new(WebContent)
if err = xml.NewDecoder(file).Decode(&w); err != nil {
log.Fatal("解析文件失败:", err)
}
// 修改数据
w.Protocol= "http"
w.Account.Password = "654321"
// 序列化XML数据,MarshalIndent后两个参数用来控制前缀和缩进
xmlData, err := xml.MarshalIndent(w, "", " ")
if err != nil {
log.Fatal(err)
}
// 覆写文件
xmlData = append([]byte(xml.Header), xmlData...)
if err = os.WriteFile(XMLFilePath, xmlData, 0777); err != nil {
log.Fatal("覆写文件失败:",err)
}
}
执行输出
bash
------------------------------
Protocol: https
Host: 192.168.100.169
Port: 80
Account:
--Username: admin
--Password: 123456
Link:
--Login: /api/login
--Index: /api/index/page
--Setting: /api/self/setting
------------------------------
------------------------------
Protocol: http
Host: 192.168.100.169
Port: 80
Account:
--Username: admin
--Password: 654321
Link:
--Login: /api/login
--Index: /api/index/page
--Setting: /api/self/setting
------------------------------