参考:https://studygolang.com/pkgdoc

导入方式:

import "encoding/xml"

实现的简单的理解XML命名空间的XML 1.0编译器

func Unmarshal —— 用于解析XML文件

func Unmarshal(data []byte, v interface{}) error

Unmarshal解析XML编码的数据并将结果存入v指向的值。v只能指向结构体、切片或者和字符串。良好格式化的数据如果不能存入v,会被丢弃。

因为Unmarshal使用reflect包,它只能填写导出字段。本函数好似用大小写敏感的比较来匹配XML元素名和结构体的字段名/标签键名。

Unmarshal函数使用如下规则将XML元素映射到结构体字段上。这些规则中,字段标签指的是结构体字段的标签键'xml'对应的值(参见上面的例子):

* 如果结构体字段的类型为字符串或者[]byte,且标签为",innerxml",Unmarshal函数直接将对应原始XML文本写入该字段,其余规则仍适用。
* 如果结构体字段类型为xml.Name且名为XMLName,Unmarshal会将元素名写入该字段
* 如果字段XMLName的标签的格式为"name"或"namespace-URL name",XML元素必须有给定的名字(以及可选的名字空间),否则Unmarshal会返回错误。
* 如果XML元素的属性的名字匹配某个标签",attr"为字段的字段名,或者匹配某个标签为"name,attr"的字段的标签名,Unmarshal会将该属性的值写入该字段。
* 如果XML元素包含字符数据,该数据会存入结构体中第一个具有标签",chardata"的字段中,该字段可以是字符串类型或者[]byte类型。如果没有这样的字段,字符数据会丢弃。
* 如果XML元素包含注释,该数据会存入结构体中第一个具有标签",comment"的字段中,该字段可以是字符串类型或者[]byte类型。如果没有这样的字段,字符数据会丢弃。
* 如果XML元素包含一个子元素,其名称匹配格式为"a"或"a>b>c"的标签的前缀,反序列化会深入XML结构中寻找具有指定名称的元素,并将最后端的元素映射到该标签所在的结构体字段。以">"开始的标签等价于以字段名开始并紧跟着">" 的标签。
* 如果XML元素包含一个子元素,其名称匹配某个结构体类型字段的XMLName字段的标签名,且该结构体字段本身没有显式指定标签名,Unmarshal会将该元素映射到该字段。
* 如果XML元素的包含一个子元素,其名称匹配够格结构体字段的字段名,且该字段没有任何模式选项(",attr"、",chardata"等),Unmarshal会将该元素映射到该字段。
* 如果XML元素包含的某个子元素不匹配以上任一条,而存在某个字段其标签为",any",Unmarshal会将该元素映射到该字段。
* 匿名字段被处理为其字段好像位于外层结构体中一样。
* 标签为"-"的结构体字段永不会被反序列化填写。

Unmarshal函数将XML元素写入string或[]byte时,会将该元素的字符数据串联起来作为值,目标[]byte不能是nil。

Unmarshal函数将属性写入string或[]byte时,会将属性的值以字符串/切片形式写入。

Unmarshal函数将XML元素写入切片时,会将切片扩展并将XML元素的子元素映射入新建的值里。

Unmarshal函数将XML元素/属性写入bool值时,会将对应的字符串转化为布尔值。

Unmarshal函数将XML元素/属性写入整数或浮点数类型时,会将对应的字符串解释为十进制数字。不会检查溢出。

Unmarshal函数将XML元素写入xml.Name类型时,会记录元素的名称。

Unmarshal函数将XML元素写入指针时,会申请一个新值并将XML元素映射入该值。

举例:

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>

举例:

package main
import("fmt""encoding/xml""io/ioutil""os""log"
)
type Recurlyservers struct {//后面的内容是struct tag,标签,是用来辅助反射的XMLName xml.Name `xml:"servers"` //将元素名写入该字段Version string `xml:"version,attr"` //将version该属性的值写入该字段Svs []server `xml:"server"`Description string `xml:",innerxml"` //Unmarshal函数直接将对应原始XML文本写入该字段
}type server struct{XMLName xml.Name `xml:"server"`ServerName string `xml:"serverName"`ServerIP string `xml:"serverIP"`
}
func main() {file, err := os.Open("servers.xml")if err != nil {log.Fatal(err)}defer file.Close()data, err := ioutil.ReadAll(file)if err != nil {log.Fatal(err)}v := Recurlyservers{}err = xml.Unmarshal(data, &v)if err != nil {log.Fatal(err)}fmt.Println(v) fmt.Printf("XMLName: %#v\n", v.XMLName)fmt.Printf("Version: %q\n", v.Version)fmt.Printf("Server: %v\n", v.Svs)for i, svs := range v.Svs{fmt.Println(i)fmt.Printf("Server XMLName: %#v\n", svs.XMLName)fmt.Printf("Server ServerName: %q\n", svs.ServerName)fmt.Printf("Server ServerIP: %q\n", svs.ServerIP)        }fmt.Printf("Description: %q\n", v.Description)}

返回:

userdeMBP:go-learning user$ go run test.go
{{ 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>
}
XMLName: xml.Name{Space:"", Local:"servers"}
Version: "1"
Server: [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
0
Server XMLName: xml.Name{Space:"", Local:"server"}
Server ServerName: "Shanghai_VPN"
Server ServerIP: "127.0.0.1"
1
Server XMLName: xml.Name{Space:"", Local:"server"}
Server ServerName: "Beijing_VPN"
Server ServerIP: "127.0.0.2"
Description: "\n    <server>\n        <serverName>Shanghai_VPN</serverName>\n        <serverIP>127.0.0.1</serverIP>\n    </server>\n    <server>\n        <serverName>Beijing_VPN</serverName>\n        <serverIP>127.0.0.2</serverIP>\n    </server>\n"

生成XML文件使用下面的两个函数:

func Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal函数返回v的XML编码。

Marshal处理数组或者切片时会序列化每一个元素。Marshal处理指针时,会序列化其指向的值;如果指针为nil,则啥也不输出。Marshal处理接口时,会序列化其内包含的具体类型值,如果接口值为nil,也是不输出。Marshal处理其余类型数据时,会输出一或多个包含数据的XML元素。

XML元素的名字按如下优先顺序获取:

- 如果数据是结构体,其XMLName字段的标签
- 类型为xml.Name的XMLName字段的值
- 数据是某结构体的字段,其标签
- 数据是某结构体的字段,其字段名
- 被序列化的类型的名字

一个结构体的XML元素包含该结构体所有导出字段序列化后的元素,有如下例外:

- XMLName字段,如上所述,会省略
- 具有标签"-"的字段会省略
- 具有标签"name,attr"的字段会成为该XML元素的名为name的属性
- 具有标签",attr"的字段会成为该XML元素的名为字段名的属性
- 具有标签",chardata"的字段会作为字符数据写入,而非XML元素
- 具有标签",innerxml"的字段会原样写入,而不会经过正常的序列化过程
- 具有标签",comment"的字段作为XML注释写入,而不经过正常的序列化过程,该字段内不能有"--"字符串
- 标签中包含"omitempty"选项的字段如果为空值会省略空值为false、0、nil指针、nil接口、长度为0的数组、切片、映射
- 匿名字段(其标签无效)会被处理为其字段是外层结构体的字段

如果一个字段的标签为"a>b>c",则元素c将会嵌套进其上层元素a和b中。如果该字段相邻的字段标签指定了同样的上层元素,则会放在同一个XML元素里。

参见MarshalIndent的例子。如果要求Marshal序列化通道、函数或者映射会返回错误。

func MarshalIndent

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

MarshalIndent功能类似Marshal。但每个XML元素会另起一行并缩进,该行以prefix起始,后跟一或多个indent的拷贝(根据嵌套层数)。它只是多了缩进的设定,使得生成的XML文件可读性更高

两个函数第一个参数是用来生成XML的结构定义类型数据,都是返回生成的XML数据流

举例生成上面解析的XML文件:

package main
import("fmt""encoding/xml" "os" ) type Servers struct {//后面的内容是struct tag,标签,是用来辅助反射的 XMLName xml.Name `xml:"servers"` //将元素名写入该字段 Version string `xml:"version,attr"` //将version该属性的值写入该字段 Svs []server `xml:"server"` } type server struct{ ServerName string `xml:"serverName"` ServerIP string `xml:"serverIP"` } func main() { v := &Servers{Version : "1"} v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"}) v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"}) //每个XML元素会另起一行并缩进,每行以prefix(这里为两个空格)起始,后跟一或多个indent(这里为四个空格)的拷贝(根据嵌套层数) //即第一层嵌套只递进四个空格,第二层嵌套则递进八个空格 output, err := xml.MarshalIndent(v," ", " ") if err != nil{ fmt.Printf("error : %v\n", err) } os.Stdout.Write([]byte(xml.Header)) //输出预定义的xml头 <?xml version="1.0" encoding="UTF-8"?>  os.Stdout.Write(output) }

返回:

userdeMBP:go-learning user$ go run test.go
<?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头的,为了生成正确的xml文件,需要使用xml包预定义的Header变量

Constants

const (// 适用于本包Marshal输出的一般性XML header// 本常数并不会自动添加到本包的输出里,这里提供主要是出于便利的目的Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
)

另一个例子:

package main
import("fmt""encoding/xml" "os" ) type Address struct { City, State string } type Person struct { XMLName xml.Name `xml:"person"` //该XML文件的根元素为person Id int `xml:"id,attr"` //该值会作为person元素的属性 FirstName string `xml:"name>first"` //first为name的子元素 LastName string `xml:"name>last"` //last Age int `xml:"age"` Height float32 `xml:"height,omitempty"` //含omitempty选项的字段如果为空值会省略 Married bool //默认为false Address //匿名字段(其标签无效)会被处理为其字段是外层结构体的字段,所以没有Address这个元素,而是直接显示City, State这两个元素 Comment string `xml:",comment"` //注释 } func main() { v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} v.Comment = " Need more details. " v.Address = Address{"Hanga Roa", "Easter Island"} output, err := xml.MarshalIndent(v, " ", " ") if err != nil { fmt.Printf("error: %v\n", err) } os.Stdout.Write(output) }

返回:

userdeMBP:go-learning user$ go run test.go<person id="13"><name><first>John</first><last>Doe</last></name><age>42</age><Married>false</Married> <City>Hanga Roa</City> <State>Easter Island</State> <!-- Need more details. --> </person>

如果是用的是xml.Marshal(v),返回为:

userdeMBP:go-learning user$ go run test.go
<person id="13"><name><first>John</first><last>Doe</last></name><age>42</age><Married>false</Married><City>Hanga Roa</City><State>Easter Island</State><!-- Need more details. --></person>

可读性就会变得差很多

未完待续

转载于:https://www.cnblogs.com/wanghui-garcia/p/10430013.html

go标准库的学习-encoding/xml相关推荐

  1. go标准库的学习-encoding/json

    参考https://studygolang.com/pkgdoc 导入方式: import "encoding/json" json包实现了json对象的编解码,参见RFC 462 ...

  2. go标准库的学习-crypto/sha1

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha1" sha1包实现了SHA1哈希算法,参见RFC 3174. ...

  3. 《C++标准库》学习笔记 — STL —流

    <C++标准库>学习笔记 - STL -流 一.操控器 1.原理 2.自定义操控器 3.控制输入的宽度 二.自定义 I/O 操作符 1.重载输出操作符 2.输入操作符 三.自定义格式化标志 ...

  4. C++“准”标准库Boost学习指南(1):智能指针Boost.smart_ptr

    我们学习C++都知道智能指针,例如STL中的std::auto_ptr,但是为什么要使用智能指针,使用它能带给我们什么好处呢? 最简单的使用智能指针可以不会因为忘记delete指针而造成内存泄露.还有 ...

  5. python标准库之socket_python标准库SocketServer学习

    导语:大牛们常常说阅读源码是很低效的学习方法.但对我辈初学者而言,阅读源码却是掌握编程思想.编码规范的好途径.简而言之,读源码不是万能的,不读源码是万万不能的. SocketServer是标准库中一个 ...

  6. c++标准库--cstdio学习

    cstdio学习 宏 类型 函数 printf() scanf 输出 源代码 宏 EOF :表示已到达文件结尾或发出其他一些故障情况 NULL:表示空指针 类型 FILE:包含控制流的信息的对象 函数 ...

  7. go标准库的学习-crypto/aes

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/aes" aes包实现了AES加密算法,参见U.S. Federal ...

  8. go标准库的学习-sync互斥

    https://studygolang.com/pkgdoc 导入方法: import "sync" sync包提供了基本的同步基元,如互斥锁.除了Once和WaitGroup类型 ...

  9. go标准库的学习-time

    参考https://studygolang.com/pkgdoc 导入形式: import "time" time包提供了时间的显示和测量用的函数.日历的计算采用的是公历. 1&g ...

最新文章

  1. 网络管理技术(Network Administrative Techniques)
  2. 《From Java To Kotlin》-Kotlin与Java的简单对比
  3. VUE搭建手机商城心得
  4. Windows Batch [精华]
  5. 比尔盖茨,马斯克、霍金都告诉你:为什么要警惕人工智能(中)
  6. ffmpeg文档2:输出到屏幕
  7. 数据结构与索引-- B+树索引
  8. 计算机应用常用的30个函数,Excel中常用函数的使用
  9. MySQL 引擎 阿里_MySQL引擎讲解-阿里云开发者社区
  10. prototype 对象的进一步深入理解
  11. ASP.NET学生考勤管理系统【源码分享】
  12. linux 定时关机命令,linux 定时关机命令
  13. Pr 视频效果:模糊与锐化
  14. 2019年中国大学生计算机设计大赛国赛答辩
  15. 银行简历计算机等级填错了,填错这几点,银行实习简历通过率几乎为0!
  16. 三星董事长去世享年78岁,临终前最为遗憾的一件事
  17. 【第二十篇】Flowable中的任务回退
  18. SCI、EI、IEEE、检索网站的区别
  19. 未来办公利器-无影云超级桌面体验
  20. 绿色债券数据最新(2014-2023年)

热门文章

  1. Ubuntu无法正常输入英文单引号符号 + 误删除package导致系统设置异常(解决方案)...
  2. postgreSQL入门01-安装
  3. 高端ERP软件市场漫谈:崇洋无罪 自重有理
  4. 何雯娜 (为奥运冠军名字作诗)
  5. Interface Collector
  6. 登录及注册模块设置与流程图
  7. Angular JS 中的内置方法之$watch
  8. android,面向对象
  9. Storm架构和编程模型总结
  10. freemarker模板引擎 常用标签