go标准库的学习-encoding/xml
参考: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="">
<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} [{{ 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: ""
Server: [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}] Server XMLName: xml.Name{Space:"", Local:"server"}
Server ServerName: "Shanghai_VPN"
Server ServerIP: "127.0.0.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、、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>
可读性就会变得差很多
未完待续
go标准库的学习-encoding/xml的更多相关文章
- go标准库的学习-encoding/base64
参考:https://studygolang.com/pkgdoc 导入方式: import "encoding/base64" base64实现了RFC 4648规定的base6 ...
- go标准库的学习-encoding/json
参考https://studygolang.com/pkgdoc 导入方式: import "encoding/json" json包实现了json对象的编解码,参见RFC 462 ...
- go标准库的学习-net/http
参考:https://studygolang.com/pkgdoc 概念解释: request:用户请求的信息,用来解析用户的请求信息,包括post.get.cookie.url等信息 respons ...
- go标准库的学习-database/sql
参考:https://studygolang.com/pkgdoc 导入方式: import "database/sql" sql包提供了保证SQL或类SQL数据库的泛用接口. 使 ...
- go标准库的学习-crypto/md5
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/md5" md5包实现了MD5哈希算法,参见RFC 1321. Con ...
- go标准库的学习-crypto/sha1
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha1" sha1包实现了SHA1哈希算法,参见RFC 3174. ...
- go标准库的学习-crypto/sha256
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha256" sha256包实现了SHA224和SHA256哈希算法 ...
- python 标准库基础学习之开发工具部分1学习
#2个标准库模块放一起学习,这样减少占用地方和空间#标准库之compileall字节编译源文件import compileall,re,sys#作用是查找到python文件,并把它们编译成字节码表示, ...
- python calendar标准库基础学习
# -*- coding: utf-8 -*-# 作者:新手__author__ = 'Administrator'#标准库:日期时间基础学习:calendar:处理日期#例1import calen ...
随机推荐
- 图解Docker容器和镜像
图解Docker容器和镜像 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(container)和镜像(image)之间的区别,并深入探讨容器和运行中的容器之间的区别. 当我对Docke ...
- LeetCode 键盘行-Python3.7<四>
500. 键盘行 题目网址:https://leetcode-cn.com/problems/keyboard-row/hints/ 给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词. ...
- Linux-kill命令和killall命令(11)
kill:指定将信号发送给某个进程,常用来杀掉进程,可以通过ps.top命令来查看进程 在默认情况下: 采用编号为的TERM信号.TERM信号将终止所有不能捕获该信号的进程. 对于那些可以捕获该信号的 ...
- 10个JavaScript难点
译者按: 能够读懂这篇博客的JavaScript开发者,运气不会太差... 原文: 10 JavaScript concepts every Node.js programmer must maste ...
- ORM&MySQL
概念: ORM:对象关系映射 , 全拼 Object-Relation Mapping ,是一种为了解决面向对象与关系数据库存在的互不匹配现象的技术.主要实现模型对象到关系型数据库数据的映射.比如:把 ...
- 图的遍历(bfs+dfs)模板
bfs #include<iostream> #include<queue> #include<cstdio> using namespace std; queue ...
- BZOJ4259: 残缺的字符串(FFT 字符串匹配)
题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...
- linux学习笔记-目录结构(2)
2./usr的意义与内容 依据FHS的基本定义,/usr里面放置的数据属于可分享的与不可变动的. usr是UNIX Software Resource的缩写,即UNIX操作系统软件资源所放置的目录,而 ...
- JSP内置对象——pageContext对象和config对象
它对应的常用方法有: 现在,我新建一个“pageContext.jsp”页面,可以获得“session_page1.jsp”这个页面中保存的用户名: pageContext.jap: session_ ...
- MySQL5.7 GTID学习笔记,[MySQL 5.6] GTID实现、运维变化及存在的bug
GTID(global transaction identifier)是对于一个已提交事务的全局唯一编号,前一部分是server_uuid,后面一部分是执行事务的唯一标志,通常是自增的. 下表整理 ...