Skip to content

Commit 0559b2f

Browse files
committedJun 10, 2017
Format and remove 07.1.md spaces
1 parent 370e95b commit 0559b2f

File tree

1 file changed

+119
-119
lines changed

1 file changed

+119
-119
lines changed
 

‎zh/07.1.md

+119-119
Original file line numberDiff line numberDiff line change
@@ -6,95 +6,95 @@ XML作为一种数据交换和信息传递的格式已经十分普及。而随
66
假如你是一名运维人员,你为你所管理的所有服务器生成了如下内容的xml的配置文件:
77
```xml
88

9-
<?xml version="1.0" encoding="utf-8"?>
10-
<servers version="1">
11-
<server>
12-
<serverName>Shanghai_VPN</serverName>
13-
<serverIP>127.0.0.1</serverIP>
14-
</server>
15-
<server>
16-
<serverName>Beijing_VPN</serverName>
17-
<serverIP>127.0.0.2</serverIP>
18-
</server>
19-
</servers>
9+
<?xml version="1.0" encoding="utf-8"?>
10+
<servers version="1">
11+
<server>
12+
<serverName>Shanghai_VPN</serverName>
13+
<serverIP>127.0.0.1</serverIP>
14+
</server>
15+
<server>
16+
<serverName>Beijing_VPN</serverName>
17+
<serverIP>127.0.0.2</serverIP>
18+
</server>
19+
</servers>
2020
```
2121
上面的XML文档描述了两个服务器的信息,包含了服务器名和服务器的IP信息,接下来的Go例子以此XML描述的信息进行操作。
2222

2323
## 解析XML
2424
如何解析如上这个XML文件呢? 我们可以通过xml包的`Unmarshal`函数来达到我们的目的
2525
```Go
2626

27-
func Unmarshal(data []byte, v interface{}) error
27+
func Unmarshal(data []byte, v interface{}) error
2828
```
2929
data接收的是XML数据流,v是需要输出的结构,定义为interface,也就是可以把XML转换为任意的格式。我们这里主要介绍struct的转换,因为struct和XML都有类似树结构的特征。
3030

3131
示例代码如下:
3232
```Go
3333

34-
package main
35-
36-
import (
37-
"encoding/xml"
38-
"fmt"
39-
"io/ioutil"
40-
"os"
41-
)
42-
43-
type Recurlyservers struct {
44-
XMLName xml.Name `xml:"servers"`
45-
Version string `xml:"version,attr"`
46-
Svs []server `xml:"server"`
47-
Description string `xml:",innerxml"`
34+
package main
35+
36+
import (
37+
"encoding/xml"
38+
"fmt"
39+
"io/ioutil"
40+
"os"
41+
)
42+
43+
type Recurlyservers struct {
44+
XMLName xml.Name `xml:"servers"`
45+
Version string `xml:"version,attr"`
46+
Svs []server `xml:"server"`
47+
Description string `xml:",innerxml"`
48+
}
49+
50+
type server struct {
51+
XMLName xml.Name `xml:"server"`
52+
ServerName string `xml:"serverName"`
53+
ServerIP string `xml:"serverIP"`
54+
}
55+
56+
func main() {
57+
file, err := os.Open("servers.xml") // For read access.
58+
if err != nil {
59+
fmt.Printf("error: %v", err)
60+
return
4861
}
49-
50-
type server struct {
51-
XMLName xml.Name `xml:"server"`
52-
ServerName string `xml:"serverName"`
53-
ServerIP string `xml:"serverIP"`
62+
defer file.Close()
63+
data, err := ioutil.ReadAll(file)
64+
if err != nil {
65+
fmt.Printf("error: %v", err)
66+
return
5467
}
55-
56-
func main() {
57-
file, err := os.Open("servers.xml") // For read access.
58-
if err != nil {
59-
fmt.Printf("error: %v", err)
60-
return
61-
}
62-
defer file.Close()
63-
data, err := ioutil.ReadAll(file)
64-
if err != nil {
65-
fmt.Printf("error: %v", err)
66-
return
67-
}
68-
v := Recurlyservers{}
69-
err = xml.Unmarshal(data, &v)
70-
if err != nil {
71-
fmt.Printf("error: %v", err)
72-
return
73-
}
74-
75-
fmt.Println(v)
68+
v := Recurlyservers{}
69+
err = xml.Unmarshal(data, &v)
70+
if err != nil {
71+
fmt.Printf("error: %v", err)
72+
return
7673
}
7774

75+
fmt.Println(v)
76+
}
77+
7878
```
7979
XML本质上是一种树形的数据格式,而我们可以定义与之匹配的go 语言的 struct类型,然后通过xml.Unmarshal来将xml中的数据解析成对应的struct对象。如上例子输出如下数据
8080
```xml
8181

82-
{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
83-
<server>
84-
<serverName>Shanghai_VPN</serverName>
85-
<serverIP>127.0.0.1</serverIP>
86-
</server>
87-
<server>
88-
<serverName>Beijing_VPN</serverName>
89-
<serverIP>127.0.0.2</serverIP>
90-
</server>
91-
}
82+
{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
83+
<server>
84+
<serverName>Shanghai_VPN</serverName>
85+
<serverIP>127.0.0.1</serverIP>
86+
</server>
87+
<server>
88+
<serverName>Beijing_VPN</serverName>
89+
<serverIP>127.0.0.2</serverIP>
90+
</server>
91+
}
9292

9393
```
9494
上面的例子中,将xml文件解析成对应的struct对象是通过`xml.Unmarshal`来完成的,这个过程是如何实现的?可以看到我们的struct定义后面多了一些类似于`xml:"serverName"`这样的内容,这个是struct的一个特性,它们被称为 struct tag,它们是用来辅助反射的。我们来看一下`Unmarshal`的定义:
9595
```Go
9696

97-
func Unmarshal(data []byte, v interface{}) error
97+
func Unmarshal(data []byte, v interface{}) error
9898
```
9999
我们看到函数定义了两个参数,第一个是XML数据流,第二个是存储的对应类型,目前支持struct、slice和string,XML包内部采用了反射来进行数据的映射,所以v里面的字段必须是导出的。`Unmarshal`解析的时候XML元素和字段怎么对应起来的呢?这是有一个优先级读取流程的,首先会读取struct tag,如果没有,那么就会对应字段名。必须注意一点的是解析的时候tag、字段名、XML元素都是大小写敏感的,所以必须一一对应字段。
100100

@@ -106,14 +106,14 @@ Go语言的反射机制,可以利用这些tag信息来将来自XML文件中的
106106

107107
```xml
108108

109-
<server>
110-
<serverName>Shanghai_VPN</serverName>
111-
<serverIP>127.0.0.1</serverIP>
112-
</server>
113-
<server>
114-
<serverName>Beijing_VPN</serverName>
115-
<serverIP>127.0.0.2</serverIP>
116-
</server>
109+
<server>
110+
<serverName>Shanghai_VPN</serverName>
111+
<serverIP>127.0.0.1</serverIP>
112+
</server>
113+
<server>
114+
<serverName>Beijing_VPN</serverName>
115+
<serverIP>127.0.0.2</serverIP>
116+
</server>
117117

118118
```
119119

@@ -133,61 +133,61 @@ Go语言的反射机制,可以利用这些tag信息来将来自XML文件中的
133133
假若我们不是要解析如上所示的XML文件,而是生成它,那么在go语言中又该如何实现呢? xml包中提供了`Marshal`和`MarshalIndent`两个函数,来满足我们的需求。这两个函数主要的区别是第二个函数会增加前缀和缩进,函数的定义如下所示:
134134
```Go
135135

136-
func Marshal(v interface{}) ([]byte, error)
137-
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
136+
func Marshal(v interface{}) ([]byte, error)
137+
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
138138
```
139139
两个函数第一个参数是用来生成XML的结构定义类型数据,都是返回生成的XML数据流。
140140

141141
下面我们来看一下如何输出如上的XML:
142142
```Go
143143

144-
package main
145-
146-
import (
147-
"encoding/xml"
148-
"fmt"
149-
"os"
150-
)
151-
152-
type Servers struct {
153-
XMLName xml.Name `xml:"servers"`
154-
Version string `xml:"version,attr"`
155-
Svs []server `xml:"server"`
144+
package main
145+
146+
import (
147+
"encoding/xml"
148+
"fmt"
149+
"os"
150+
)
151+
152+
type Servers struct {
153+
XMLName xml.Name `xml:"servers"`
154+
Version string `xml:"version,attr"`
155+
Svs []server `xml:"server"`
156+
}
157+
158+
type server struct {
159+
ServerName string `xml:"serverName"`
160+
ServerIP string `xml:"serverIP"`
161+
}
162+
163+
func main() {
164+
v := &Servers{Version: "1"}
165+
v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"})
166+
v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"})
167+
output, err := xml.MarshalIndent(v, " ", " ")
168+
if err != nil {
169+
fmt.Printf("error: %v\n", err)
156170
}
171+
os.Stdout.Write([]byte(xml.Header))
157172

158-
type server struct {
159-
ServerName string `xml:"serverName"`
160-
ServerIP string `xml:"serverIP"`
161-
}
162-
163-
func main() {
164-
v := &Servers{Version: "1"}
165-
v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"})
166-
v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"})
167-
output, err := xml.MarshalIndent(v, " ", " ")
168-
if err != nil {
169-
fmt.Printf("error: %v\n", err)
170-
}
171-
os.Stdout.Write([]byte(xml.Header))
172-
173-
os.Stdout.Write(output)
174-
}
173+
os.Stdout.Write(output)
174+
}
175175

176176
```
177177
上面的代码输出如下信息:
178178
```xml
179179

180-
<?xml version="1.0" encoding="UTF-8"?>
181-
<servers version="1">
182-
<server>
183-
<serverName>Shanghai_VPN</serverName>
184-
<serverIP>127.0.0.1</serverIP>
185-
</server>
186-
<server>
187-
<serverName>Beijing_VPN</serverName>
188-
<serverIP>127.0.0.2</serverIP>
189-
</server>
190-
</servers>
180+
<?xml version="1.0" encoding="UTF-8"?>
181+
<servers version="1">
182+
<server>
183+
<serverName>Shanghai_VPN</serverName>
184+
<serverIP>127.0.0.1</serverIP>
185+
</server>
186+
<server>
187+
<serverName>Beijing_VPN</serverName>
188+
<serverIP>127.0.0.2</serverIP>
189+
</server>
190+
</servers>
191191

192192
```
193193
和我们之前定义的文件的格式一模一样,之所以会有`os.Stdout.Write([]byte(xml.Header))` 这句代码的出现,是因为`xml.MarshalIndent`或者`xml.Marshal`输出的信息都是不带XML头的,为了生成正确的xml文件,我们使用了xml包预定义的Header变量。
@@ -220,13 +220,13 @@ Go语言的反射机制,可以利用这些tag信息来将来自XML文件中的
220220
- tag中含有`"a>b>c"`,那么就会循环输出三个元素a包含b,b包含c,例如如下代码就会输出
221221

222222
```xml
223-
FirstName string `xml:"name>first"`
224-
LastName string `xml:"name>last"`
223+
FirstName string `xml:"name>first"`
224+
LastName string `xml:"name>last"`
225225

226-
<name>
227-
<first>Asta</first>
228-
<last>Xie</last>
229-
</name>
226+
<name>
227+
<first>Asta</first>
228+
<last>Xie</last>
229+
</name>
230230

231231
```
232232
上面我们介绍了如何使用Go语言的xml包来编/解码XML文件,重要的一点是对XML的所有操作都是通过struct tag来实现的,所以学会对struct tag的运用变得非常重要,在文章中我们简要的列举了如何定义tag。更多内容或tag定义请参看相应的官方资料。

0 commit comments

Comments
 (0)
Please sign in to comment.