生命不止,继续 go go go !!!
介绍了encoding/json包的使用,就没有理由不介绍encoding/xml包。
xml vs json
xml和json都是文本表示的数据格式:
跨平台
跨系统交换数据
但是,XML更适合标记文档,JSON更适合数据交互。
两者最大的不同在于,XML是一个完整的标记语言,而JSON不是。XML利用标记语言的特性提供了绝佳的延展性(如XPath),在数据存储,扩展及高级检索方面优势明显。
而JSON则由于比XML更加小巧,以及浏览器的内建快速解析支持,使得其更适用于网络数据传输领域。
就可读性而言,两者都具备很好的可读性,但XML文档的可读性更高。
就数据表示和传输性能而言,JSON明显比XML简洁,格式简单,占用带宽少。
例子:json
{"employees":[ { "firstName":"John","lastName":"Doe" },{ "firstName":"Anna","lastName":"Smith" },{ "firstName":"Peter","lastName":"Jones" } ]}
例子:xml
<employees>
<employee>
<firstName>John</firstName> <lastName>Doe</lastName>
</employee>
<employee>
<firstName>Anna</firstName> <lastName>Smith</lastName>
</employee>
<employee>
<firstName>Peter</firstName> <lastName>Jones</lastName>
</employee>
</employees>
JSON
Simple Syntax,which results in less “markup” overhead compared to XML.
Easy to use with JavaScript as the markup is a subset of JS object literal notation and has the same basic data types as JavaScript.
JSON Schema for description and datatype and structure validation
JsonPath for extracting @R_247_4045@ion in deeply nested structures
XML
Generalized markup; it is possible to create “dialects” for any kind of purpose
XML Schema for datatype,structure validation. Makes it also possible to create new datatypes
XSLT for transformation into different output formats
XPath/XQuery for extracting @R_247_4045@ion in deeply nested structures
built in support for namespaces
下面开始正式介绍go中如何操作xml的,当然为我们提供了encoding/xml package。
encoding/xml
作用:
Package xml implements a simple XML 1.0 parser that understands XML name spaces.
xml 包实现了一个简单的 XML 1.0 语法分析器, 这个分析器能够理解 XML 命名空间。
常量
const (
// A generic XML header suitable for use with the output of Marshal.
// This is not automatically added to any output of this package,
// it is provided as a convenience.
Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
)
Marshal 函数
func Marshal(v interface{}) ([]byte,error)
Marshal returns the XML encoding of v.
Marshal 在遇到一个数组或切片时, 会对其包含的每个元素进行封装; 在遇到指针时, 会对指针的值进行封装, 并忽略那些未 nil 的指针; 在遇到接口时, 会对接口包含的值进行封装, 并忽略那些值为 nil 的接口; 在遇到其他数据时, Marshal 将写入一个或多个包含这些数据的 XML 元素。
在进行封装时, XML 元素的名字由一系列规则决定, 这些规则的优先级从高到低依次为:
- 如果给定的数据是一个结构, 那么使用 XMLName 字段的标签作为元素名
- 使用类型为 Name 的 XMLName 字段的值为元素名
- 将用于获取数据的结构字段的标签用作元素名
- 将用于获取数据的结构字段的名字用作元素名
- 将被封装类型的名字用作元素名
结构中的每个已导出字段都会被封装为相应的元素并包含在 XML 里面, 但以下规则中提到的内容除外:
-XMLName 字段,因为前面提到的原因,会被忽略
- 带有 “-” 标签的字段会被忽略
- 带有 “name,attr” 标签的字段会成为 XML 元素的属性, 其中属性的名字为这里给定的 name
- 带有 ”,attr” 标签的字段会成为 XML 元素的属性, 其中属性的名字为字段的名字
- 带有 ”,chardata” 标签的字段将会被封装为字符数据而不是 XML 元素。
- 带有 ”,cdata” 标签的字段将会被封装为字符数据而不是 XML 元素, 并且这些数据还会被一个或多个
func Unmarshal(data []byte,v interface{}) error
Unmarshal parses the XML-encoded data and stores the result in the value pointed to by v,which must be an arbitrary struct,slice,or string. well-formed data that does not fit into v is discarded.
例子:
package main
import (
"encoding/xml"
"fmt"
"os"
)
func main() {
type Address struct {
City,State string
}
type Person struct {
XMLName xml.Name `xml:"person"`
Id int `xml:"id,attr"`
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
Age int `xml:"age"`
Height float32 `xml:"height,omitempty"`
Married bool
Address
Comment string `xml:",comment"`
}
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)
fmt.Println("\n")
}
输出结果:
Unmarshal 函数
func Unmarshal(data []byte,v interface{}) error
Unmarshal 会对 XML 编码的数据进行语法分析, 并将结果储存到 v 指向的值里面, 其中 v 必须是一个任意的(arbitrary)结构、切片或者字符串。 格式良好但是无法放入到 v 里面的数据将被抛弃。
例子:
package main
import (
"encoding/xml"
"fmt"
)
func main() {
type Email struct {
Where string `xml:"where,attr"`
Addr string
}
type Address struct {
City,State string
}
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
v := Result{Name: "none",Phone: "none"}
data := ` <Person> <FullName>Grace R. Emlin</FullName> <Company>Example Inc.</Company> <Email where="home"> <Addr>[email protected]</Addr> </Email> <Email where='work'> <Addr>[email protected]</Addr> </Email> <Group> <Value>Friends</Value> <Value>Squash</Value> </Group> <City>Hanga Roa</City> <State>Easter Island</State> </Person> `
err := xml.Unmarshal([]byte(data),&v)
if err != nil {
fmt.Printf("error: %v",err)
return
}
fmt.Printf("XMLName: %#v\n",v.XMLName)
fmt.Printf("Name: %q\n",v.Name)
fmt.Printf("Phone: %q\n",v.Phone)
fmt.Printf("Email: %v\n",v.Email)
fmt.Printf("Groups: %v\n",v.Groups)
fmt.Printf("Address: %v\n",v.Address)
}
运行结果:
Decoder
A Decoder represents an XML parser reading a particular input stream. The parser assumes that its input is encoded in UTF-8.
NewDecoder 函数
func NewDecoder(r io.Reader) *Decoder
创建一个新的读取 r 的 XML 语法分析器。 如果 r 没有实现 io.ByteReader , 那么函数将使用它自有的缓冲机制。
(*Decoder) Decode 方法
func (d *Decoder) Decode(v interface{}) error
执行与 Unmarshal 一样的解码工作, 唯一的不同在于这个方法会通过读取解码器流来查找起始元素。
Encoder
Encoder 负责把 XML 数据写入至输出流里面。
NewEncoder 函数
func NewEncoder(w io.Writer) *Encoder
返回一个能够对 w 进行写入的编码器。
(*Encoder) Encode 方法
func (enc *Encoder) Encode(v interface{}) error
将 XML 编码的 v 写入到流里面。