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

导入方式:

  1. import "encoding/xml"

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

func Unmarshal —— 用于解析XML文件

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

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

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

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

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

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文件为:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <servers version="">
  3. <server>
  4. <serverName>Shanghai_VPN</serverName>
  5. <serverIP>127.0.0.1</serverIP>
  6. </server>
  7. <server>
  8. <serverName>Beijing_VPN</serverName>
  9. <serverIP>127.0.0.2</serverIP>
  10. </server>
  11. </servers>

举例:

  1. package main
  2. import(
  3. "fmt"
  4. "encoding/xml"
  5. "io/ioutil"
  6. "os"
  7. "log"
  8. )
  9. type Recurlyservers struct {//后面的内容是struct tag,标签,是用来辅助反射的
  10. XMLName xml.Name `xml:"servers"` //将元素名写入该字段
  11. Version string `xml:"version,attr"` //将version该属性的值写入该字段
  12. Svs []server `xml:"server"`
  13. Description string `xml:",innerxml"` //Unmarshal函数直接将对应原始XML文本写入该字段
  14. }
  15.  
  16. type server struct{
  17. XMLName xml.Name `xml:"server"`
  18. ServerName string `xml:"serverName"`
  19. ServerIP string `xml:"serverIP"`
  20. }
  21. func main() {
  22. file, err := os.Open("servers.xml")
  23. if err != nil {
  24. log.Fatal(err)
  25. }
  26.  
  27. defer file.Close()
  28. data, err := ioutil.ReadAll(file)
  29. if err != nil {
  30. log.Fatal(err)
  31. }
  32.  
  33. v := Recurlyservers{}
  34. err = xml.Unmarshal(data, &v)
  35. if err != nil {
  36. log.Fatal(err)
  37. }
  38. fmt.Println(v)
  39.  
  40. fmt.Printf("XMLName: %#v\n", v.XMLName)
  41. fmt.Printf("Version: %q\n", v.Version)
  42.  
  43. fmt.Printf("Server: %v\n", v.Svs)
  44. for i, svs := range v.Svs{
  45. fmt.Println(i)
  46. fmt.Printf("Server XMLName: %#v\n", svs.XMLName)
  47. fmt.Printf("Server ServerName: %q\n", svs.ServerName)
  48. fmt.Printf("Server ServerIP: %q\n", svs.ServerIP)
  49. }
  50. fmt.Printf("Description: %q\n", v.Description)
  51.  
  52. }

返回:

  1. userdeMBP:go-learning user$ go run test.go
  2. {{ servers} [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
  3. <server>
  4. <serverName>Shanghai_VPN</serverName>
  5. <serverIP>127.0.0.1</serverIP>
  6. </server>
  7. <server>
  8. <serverName>Beijing_VPN</serverName>
  9. <serverIP>127.0.0.2</serverIP>
  10. </server>
  11. }
  12. XMLName: xml.Name{Space:"", Local:"servers"}
  13. Version: ""
  14. Server: [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
  15.  
  16. Server XMLName: xml.Name{Space:"", Local:"server"}
  17. Server ServerName: "Shanghai_VPN"
  18. Server ServerIP: "127.0.0.1"
  19.  
  20. Server XMLName: xml.Name{Space:"", Local:"server"}
  21. Server ServerName: "Beijing_VPN"
  22. Server ServerIP: "127.0.0.2"
  23. 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

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

Marshal函数返回v的XML编码。

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

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

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

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

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

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

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

func MarshalIndent

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

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

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

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

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

返回:

  1. userdeMBP:go-learning user$ go run test.go
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <servers version="1">
  4. <server>
  5. <serverName>Shanghai_VPN</serverName>
  6. <serverIP>127.0.0.1</serverIP>
  7. </server>
  8. <server>
  9. <serverName>Beijing_VPN</serverName>
  10. <serverIP>127.0.0.2</serverIP>
  11. </server>
  12. </servers>

需要os.Stdout.Write([]byte(xml.Header))这句代码是因为上面的两个函数输出的信息都是不带XML头的,为了生成正确的xml文件,需要使用xml包预定义的Header变量

Constants

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

另一个例子:

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

返回:

  1. userdeMBP:go-learning user$ go run test.go
  2. <person id="13">
  3. <name>
  4. <first>John</first>
  5. <last>Doe</last>
  6. </name>
  7. <age>42</age>
  8. <Married>false</Married>
  9. <City>Hanga Roa</City>
  10. <State>Easter Island</State>
  11. <!-- Need more details. -->
  12. </person>

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

  1. userdeMBP:go-learning user$ go run test.go
  2. <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>

可读性就会变得差很多

未完待续

go标准库的学习-encoding/xml的更多相关文章

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

    参考:https://studygolang.com/pkgdoc 导入方式: import "encoding/base64" base64实现了RFC 4648规定的base6 ...

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

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

  3. go标准库的学习-net/http

    参考:https://studygolang.com/pkgdoc 概念解释: request:用户请求的信息,用来解析用户的请求信息,包括post.get.cookie.url等信息 respons ...

  4. go标准库的学习-database/sql

    参考:https://studygolang.com/pkgdoc 导入方式: import "database/sql" sql包提供了保证SQL或类SQL数据库的泛用接口. 使 ...

  5. go标准库的学习-crypto/md5

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/md5" md5包实现了MD5哈希算法,参见RFC 1321. Con ...

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

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

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

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha256" sha256包实现了SHA224和SHA256哈希算法 ...

  8. python 标准库基础学习之开发工具部分1学习

    #2个标准库模块放一起学习,这样减少占用地方和空间#标准库之compileall字节编译源文件import compileall,re,sys#作用是查找到python文件,并把它们编译成字节码表示, ...

  9. python calendar标准库基础学习

    # -*- coding: utf-8 -*-# 作者:新手__author__ = 'Administrator'#标准库:日期时间基础学习:calendar:处理日期#例1import calen ...

随机推荐

  1. Hive数据倾斜

    数据倾斜是进行大数据计算时最经常遇到的问题之一.当我们在执行HiveQL或者运行MapReduce作业时候,如果遇到一直卡在map100%,reduce99%一般就是遇到了数据倾斜的问题.数据倾斜其实 ...

  2. Java框架之Spring(二)

    前一篇博客讲述了Spring的一些基础概念,下面我们来创建第一个Spring程序吧. 步骤如下: 1) 导包 2) 配置文件 附没有提示的情况 MyEclipse ->File and Edit ...

  3. Java基础——Oracle(八)

    一.流程控制语句 1) 循环语句 == loop ..  end loop 简单的循环,至少被执行一次 create table userinfo (id number, name varchar2( ...

  4. 微信小程序开发BUG经验总结

    摘要: 常见的微信小程序BUG! 小程序开发越来越热,开发中遇到各种各样的bug,在此总结了一些比较容易掉进去的坑分享给大家. 1. new Date跨平台兼容性问题 在Andriod使用new Da ...

  5. Django Rest framework 之 版本

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  6. PyCharm 添加签名和时间

    工具栏上添加上 Toolbar 点击 Editor -> File and Code Templates -> Python Script 在文本框上填写需要的数据

  7. Push notification - Caused by java.io.IOException toDerInputStream rejects tag

    苹果推送 : 文件不是P12文件当生成一个P12,需要选择两个,在钥匙串访问的私钥和证书.

  8. 【工具相关】Web-Sublime Text2的用法(一)

    一,打开Sublime Text2--->出现如下所示界面. 二,在编辑区域可以随便输入数字.如图所示. 三,File--->Save. 四,将名字加上后缀,使其成为我们希望编辑的文件类型 ...

  9. python之继承

    1.经典MRO : 树形结构的深度遍历优先 - > 树形结构遍历 class A: pass class B(A): pass class C(A): pass class D(B, C): p ...

  10. 使用CSS兄弟选择器完成复杂垂直边距(vertical margins)的设计

    -------------------sibling选择器如何在完成复杂设计要求的同时,保持CSS可读 这是web前端开发过程中开始简单逐步变的复杂的例子之一:将一篇文章中的所有元素应用垂直边距(ve ...