内容简介:XML是Web服务中常用的数据通信格式。今天,它在Web开发中扮演着越来越重要的角色。本次分享将介绍如何通过Go的标准库使用XML。我不会尝试教授XML的语法或约定。你可以去阅读有关XML本身的更多文档。我只关注如何在Go中编码和解码XML文件。假设您在IT中工作,并且您必须处理以下XML配置文件:上面的XML文档包含有关服务器的两种信息:服务器名称和IP。我们将在以下示例中使用此文档。如何解析这个XML文档?可以使用Go的xml包中的Unmarshal函数来执行此操作。
XML
XML是Web服务中常用的数据通信格式。今天,它在Web开发中扮演着越来越重要的角色。本次分享将介绍如何通过 Go 的标准库使用XML。我不会尝试教授XML的语法或约定。你可以去阅读有关XML本身的更多文档。我只关注如何在Go中编码和解码XML文件。假设您在IT中工作,并且您必须处理以下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>
上面的XML文档包含有关服务器的两种信息:服务器名称和IP。我们将在以下示例中使用此文档。
解析XML
如何解析这个XML文档?可以使用Go的xml包中的Unmarshal函数来执行此操作。
func Unmarshal(data []byte, v interface{}) error
data参数从XML源接收数据流,v是要将解析后的XML输出到的结构中。它是一个接口,这意味着您可以将XML转换为您想要的任何结构。在这里,我们只讨论如何从XML转换为结构类型,因为它们共享相似的树结构。
示例代码:
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
)
type Server struct {
XMLName xml.Name `xml:"server"`
ServerName string `xml:"serverName"`
ServerIP string `xml:"serverIP"`
}
type XMLServers struct {
XMLName xml.Name `xml:"servers"`
Version string `xml:"version,attr"`
Servers []Server `xml:"server"`
Description string `xml:",innerxml"`
}
func main() {
file, err := os.Open(config.TemplateDir + "/server.xml")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println(err)
return
}
v := XMLServers{}
err = xml.Unmarshal(data, &v)
if err != nil {
fmt.Println(err)
return
}
fmt.Fprintln(w, v)
}
XML实际上是一个树数据结构,我们可以使用Go中的结构定义一个非常相似的结构,然后使用xml.Unmarshal从XML转换为我们的struct对象。示例代码将打印以下内容:
{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
}
我们使用xml.Unmarshal将XML文档解析为相应的struct对象。您应该看到我们的结构中有xml:"serverName"。这是结构体的一个特征,称为结构标记,用于帮助反射。让我们再看一下Unmarshal的定义:
func Unmarshal(data []byte, v interface{}) error
第一个参数是XML数据流。第二个参数是存储类型,支持struct,slice和string类型。Go的XML包使用反射进行数据映射,因此应该导出v中的所有字段。但是,这会导致一个问题:它如何知道哪个XML字段对应于映射的struct字段?答案是XML解析器按特定顺序解析数据。库将首先尝试查找匹配的struct标记。如果找不到匹配,则搜索结构字段名称。请注意,所有标记,字段名称和XML元素都区分大小写,因此您必须确保映射成功时存在一对一的对应关系。Go的反射机制允许您使用此标记信息将XML数据反映到结构对象。如果您想了解有关Go中反射的更多信息,请阅读有关struct标签和反射的包文档。
使用xml包将XML文档解析为结构时,以下是一些规则:
- 如果字段类型是带有标签",innerxml"的字符串或[]字节,则Unmarshal将为其分配原始XML数据,如上例中的描述:Shanghai_VPN127.0.0.1Beijing_VPN
- 如果一个字段被称为XMLName并且其类型是xml.Name,那么它将获取元素名称,就像上面示例中的servers一样。
- 如果字段的标记包含相应的元素名称,那么它也会获取元素名称,如上例中的servername和serverip。
- 如果字段的标记包含",attr",则它获取相应元素的属性,如上例中的版本。
- 如果字段的标记包含类似"a>b>c"的内容,则它获取节点a的节点b的元素c的值。
- 如果字段的标记包含"=",那么它什么也得不到。
- 如果字段的标记包含",any",则它将获取所有不符合其他规则的子元素。
- 如果XML元素有一个或多个注释,则所有这些注释都将添加到包含",comments"的标记的第一个字段中。该字段类型可以是string或[]byte。如果此类字段不存在,则丢弃所有注释。
这些规则告诉您如何在结构中定义标记。一旦理解了这些规则,将XML映射到结构就像上面的示例代码一样简单。因为标签和XML元素具有一对一的对应关系,所以我们也可以使用切片来表示同一级别上的多个元素。请注意,结构中的所有字段都应导出(大写),以便正确解析数据。
生成XML
如果我们想要生成XML文档而不是解析XML文档,该怎么办?我们如何在Go中做到这一点?xml包提供了两个函数,即Marshal和MarshalIndent,其中第二个函数自动缩进编组的XML文档。
他们的定义如下:
func Marshal(v interface{}) ([]byte, error)
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
这两个函数中的第一个参数用于存储编组的XML数据流。让我们看一个例子,看看它是如何工作的:
package main
import (
"encoding/xml"
"fmt"
"os"
)
type Server struct {
XMLName xml.Name `xml:"server"`
ServerName string `xml:"serverName"`
ServerIP string `xml:"serverIP"`
}
type XMLServers struct {
XMLName xml.Name `xml:"servers"`
Version string `xml:"version,attr"`
Servers []Server `xml:"server"`
Description string `xml:",innerxml"`
}
func main() {
v := &XMLServers{
Version: "1",
}
v.Servers = append(v.Servers, Server{
ServerName: "Shanghai_VPN",
ServerIP: "127.0.0.1",
})
v.Servers = append(v.Servers, Server{
ServerName: "Beijing_VPN",
ServerIP: "127.0.0.2",
})
output, err := xml.MarshalIndent(v, "", " ")
if err != nil {
fmt.Println(err)
return
}
os.Stdout.Write([]byte(xml.Header))
os.Stdout.Write(output)
}
上面的示例打印以下信息:
<?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>
正如我们之前定义的那样,我们有os.Stdout.Write([] byte(xml.Header))的原因是因为xml.MarshalIndent和xml.Marshal都没有自己输出XML头,所以我们必须明确
打印它们以便正确生成XML文档。在这里我们可以看到Marshal还接收了一个类型为interface {}的v参数。那么编组XML文档时的规则是什么?
- 如果v是数组或切片,则它会打印所有元素,如value。
- 如果v是指针,则它打印v指向的内容,当v为nil时不打印任何内容。
- 如果v是一个接口,它也会处理接口。
- 如果v是其他类型之一,则打印该类型的值。
那么xml.Marshal如何决定元素的名称?它遵循随后的规则:
- 如果v是结构,则它在XMLName的标记中定义名称。
- 字段名称为XMLName,类型为xml.Name。
- struct中的字段标记。
- struct中的字段名称。
- 输入编组名称。
然后我们需要弄清楚如何设置标记以生成最终的XML文档。
- 不会打印XMLName。
- 包含"-"标签的字段将不会被打印。
- 如果标记包含"name,attr",则它使用name作为属性名称,使用字段值作为值,就像上面示例中的版本一样。
- 如果标记包含",attr",则它使用字段的名称作为属性名称,将字段值作为其值。
- 如果标签包含",chardata",则它会打印字符数据而不是元素。
- 如果标签包含",innerxml",则打印原始值。
- 如果标记包含",comment",则会将其作为注释打印而不进行转义,因此您的值不能包含"-"。
- 如果标记包含"omitempty",则如果其值为零值,则忽略该字段,包括false,0,nil指针或nil接口,数组的长度为零,slice,map和string。
- 如果标签包含"a>b>c",则打印三个元素,其中a包含b,b包含c
以上所述就是小编给大家介绍的《Go基础学习记录之如何解析并生成XML》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Java生成、解析二维码
- Python生成器以及应用实例解析
- Django源码解析|Migrations文件的生成
- golang生成JSON及解析JSON
- Python 迭代器、生成器和列表解析
- Go基础学习记录之如何解析并生成JSON
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
精通Spring
罗时飞 / 第1版 (2005年4月1日) / 2005-4 / 39.0
本书深入剖析了当前流行的轻量级开发框架Spring技术。本书总共分成3部分。第一部分,重点阐述Spring的架构。这部分内容循序渐进带领开发者进入Spring中。主要在于阐述Spring IoC和Spring AOP。第二部分,重点阐述Spring的使用。这部分内容从简化Java/J2EE的角度出发,从J2EE平台各个技术层面分析、并给出大量的研究实例,对Spring提供的API进行阐述。主要在于......一起来看看 《精通Spring》 这本书的介绍吧!
RGB转16进制工具
RGB HEX 互转工具
图片转BASE64编码
在线图片转Base64编码工具