Skip to content

Commit b3b6027

Browse files
authored
Merge pull request astaxie#851 from vCaesar/u16-pr
Add en/0.7.x.md syntax highlighting
2 parents 5952a4b + 43e55a1 commit b3b6027

File tree

6 files changed

+964
-961
lines changed

6 files changed

+964
-961
lines changed

en/07.1.md

Lines changed: 132 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ XML is a commonly used data communication format in web services. Today, it's as
55
I will not make any attempts to teach XML's syntax or conventions. For that, please read more documentation about XML itself. We will only focus on how to encode and decode XML files in Go.
66

77
Suppose you work in IT, and you have to deal with the following XML configuration file:
8-
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>
20-
8+
```xml
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>
20+
```
2121
The above XML document contains two kinds of information about your server: the server name and IP. We will use this document in our following examples.
2222

2323
## Parse XML
@@ -29,68 +29,68 @@ How do we parse this XML document? We can use the `Unmarshal` function in Go's `
2929
the `data` parameter receives a data stream from an XML source, and `v` is the structure you want to output the parsed XML to. It is an interface, which means you can convert XML to any structure you desire. Here, we'll only talk about how to convert from XML to the `struct` type since they share similar tree structures.
3030

3131
Sample code:
32-
33-
package main
34-
35-
import (
36-
"encoding/xml"
37-
"fmt"
38-
"io/ioutil"
39-
"os"
40-
)
41-
42-
type Recurlyservers struct {
43-
XMLName xml.Name `xml:"servers"`
44-
Version string `xml:"version,attr"`
45-
Svs []server `xml:"server"`
46-
Description string `xml:",innerxml"`
47-
}
48-
49-
type server struct {
50-
XMLName xml.Name `xml:"server"`
51-
ServerName string `xml:"serverName"`
52-
ServerIP string `xml:"serverIP"`
53-
}
54-
55-
func main() {
56-
file, err := os.Open("servers.xml") // For read access.
57-
if err != nil {
58-
fmt.Printf("error: %v", err)
59-
return
60-
}
61-
defer file.Close()
62-
data, err := ioutil.ReadAll(file)
63-
if err != nil {
64-
fmt.Printf("error: %v", err)
65-
return
66-
}
67-
v := Recurlyservers{}
68-
err = xml.Unmarshal(data, &v)
69-
if err != nil {
70-
fmt.Printf("error: %v", err)
71-
return
72-
}
73-
74-
fmt.Println(v)
75-
}
76-
32+
```Go
33+
package main
34+
35+
import (
36+
"encoding/xml"
37+
"fmt"
38+
"io/ioutil"
39+
"os"
40+
)
41+
42+
type Recurlyservers struct {
43+
XMLName xml.Name `xml:"servers"`
44+
Version string `xml:"version,attr"`
45+
Svs []server `xml:"server"`
46+
Description string `xml:",innerxml"`
47+
}
48+
49+
type server struct {
50+
XMLName xml.Name `xml:"server"`
51+
ServerName string `xml:"serverName"`
52+
ServerIP string `xml:"serverIP"`
53+
}
54+
55+
func main() {
56+
file, err := os.Open("servers.xml") // For read access.
57+
if err != nil {
58+
fmt.Printf("error: %v", err)
59+
return
60+
}
61+
defer file.Close()
62+
data, err := ioutil.ReadAll(file)
63+
if err != nil {
64+
fmt.Printf("error: %v", err)
65+
return
66+
}
67+
v := Recurlyservers{}
68+
err = xml.Unmarshal(data, &v)
69+
if err != nil {
70+
fmt.Printf("error: %v", err)
71+
return
72+
}
73+
74+
fmt.Println(v)
75+
}
76+
```
7777
XML is actually a tree data structure, and we can define a very similar structure using structs in Go, then use `xml.Unmarshal` to convert from XML to our struct object. The sample code will print the following content:
78-
79-
{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
80-
<server>
81-
<serverName>Shanghai_VPN</serverName>
82-
<serverIP>127.0.0.1</serverIP>
83-
</server>
84-
<server>
85-
<serverName>Beijing_VPN</serverName>
86-
<serverIP>127.0.0.2</serverIP>
87-
</server>
88-
}
89-
78+
```xml
79+
{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
80+
<server>
81+
<serverName>Shanghai_VPN</serverName>
82+
<serverIP>127.0.0.1</serverIP>
83+
</server>
84+
<server>
85+
<serverName>Beijing_VPN</serverName>
86+
<serverIP>127.0.0.2</serverIP>
87+
</server>
88+
}
89+
```
9090
We use `xml.Unmarshal` to parse the XML document to the corresponding struct object. You should see that we have something like `xml:"serverName"` in our struct. This is a feature of structs called `struct tags` for helping with reflection. Let's see the definition of `Unmarshal` again:
91-
92-
func Unmarshal(data []byte, v interface{}) error
93-
91+
```Go
92+
func Unmarshal(data []byte, v interface{}) error
93+
```
9494
The first argument is an XML data stream. The second argument is storage type and supports the struct, slice and string types. Go's XML package uses reflection for data mapping, so all fields in v should be exported. However, this causes a problem: how does it know which XML field corresponds to the mapped struct field? The answer is that the XML parser parses data in a certain order. The library will try to find the matching struct tag first. If a match cannot be found then it searches through the struct field names. Be aware that all tags, field names and XML elements are case sensitive, so you have to make sure that there is a one-to-one correspondence for the mapping to succeed.
9595

9696
Go's reflection mechanism allows you to use this tag information to reflect XML data to a struct object. If you want to know more about reflection in Go, please read the package documentation on struct tags and reflection.
@@ -116,60 +116,60 @@ Note that all fields in structs should be exported (capitalized) in order to par
116116
## Produce XML
117117

118118
What if we want to produce an XML document instead of parsing one. How do we do this in Go? Unsurprisingly, the `xml` package provides two functions which are `Marshal` and `MarshalIndent`, where the second function automatically indents the marshalled XML document. Their definition as follows:
119-
120-
func Marshal(v interface{}) ([]byte, error)
121-
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
122-
119+
```Go
120+
func Marshal(v interface{}) ([]byte, error)
121+
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
122+
```
123123
The first argument in both of these functions is for storing a marshalled XML data stream.
124124

125125
Let's look at an example to see how this works:
126-
127-
package main
128-
129-
import (
130-
"encoding/xml"
131-
"fmt"
132-
"os"
133-
)
134-
135-
type Servers struct {
136-
XMLName xml.Name `xml:"servers"`
137-
Version string `xml:"version,attr"`
138-
Svs []server `xml:"server"`
139-
}
140-
141-
type server struct {
142-
ServerName string `xml:"serverName"`
143-
ServerIP string `xml:"serverIP"`
144-
}
145-
146-
func main() {
147-
v := &Servers{Version: "1"}
148-
v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"})
149-
v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"})
150-
output, err := xml.MarshalIndent(v, " ", " ")
151-
if err != nil {
152-
fmt.Printf("error: %v\n", err)
153-
}
154-
os.Stdout.Write([]byte(xml.Header))
155-
156-
os.Stdout.Write(output)
157-
}
158-
126+
```Go
127+
package main
128+
129+
import (
130+
"encoding/xml"
131+
"fmt"
132+
"os"
133+
)
134+
135+
type Servers struct {
136+
XMLName xml.Name `xml:"servers"`
137+
Version string `xml:"version,attr"`
138+
Svs []server `xml:"server"`
139+
}
140+
141+
type server struct {
142+
ServerName string `xml:"serverName"`
143+
ServerIP string `xml:"serverIP"`
144+
}
145+
146+
func main() {
147+
v := &Servers{Version: "1"}
148+
v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"})
149+
v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"})
150+
output, err := xml.MarshalIndent(v, " ", " ")
151+
if err != nil {
152+
fmt.Printf("error: %v\n", err)
153+
}
154+
os.Stdout.Write([]byte(xml.Header))
155+
156+
os.Stdout.Write(output)
157+
}
158+
```
159159
The above example prints the following information:
160-
161-
<?xml version="1.0" encoding="UTF-8"?>
162-
<servers version="1">
163-
<server>
164-
<serverName>Shanghai_VPN</serverName>
165-
<serverIP>127.0.0.1</serverIP>
166-
</server>
167-
<server>
168-
<serverName>Beijing_VPN</serverName>
169-
<serverIP>127.0.0.2</serverIP>
170-
</server>
171-
</servers>
172-
160+
```xml
161+
<?xml version="1.0" encoding="UTF-8"?>
162+
<servers version="1">
163+
<server>
164+
<serverName>Shanghai_VPN</serverName>
165+
<serverIP>127.0.0.1</serverIP>
166+
</server>
167+
<server>
168+
<serverName>Beijing_VPN</serverName>
169+
<serverIP>127.0.0.2</serverIP>
170+
</server>
171+
</servers>
172+
```
173173
As we've previously defined, the reason we have `os.Stdout.Write([]byte(xml.Header))` is because both `xml.MarshalIndent` and `xml.Marshal` do not output XML headers on their own, so we have to explicitly print them in order to produce XML documents correctly.
174174

175175
Here we can see that `Marshal` also receives a v parameter of type `interface{}`. So what are the rules when marshalling to an XML document?
@@ -198,15 +198,15 @@ Then we need to figure out how to set tags in order to produce the final XML doc
198198
- If a tag contains `",comment"`, it prints it as a comment without escaping, so you cannot have "--" in its value.
199199
- If a tag contains `"omitempty"`, it omits this field if its value is zero-value, including false, 0, nil pointer or nil interface, zero length of array, slice, map and string.
200200
- If a tag contains `"a>b>c"`, it prints three elements where a contains b and b contains c, like in the following code:
201-
202-
FirstName string `xml:"name>first"`
203-
LastName string `xml:"name>last"`
204-
205-
<name>
206-
<first>Asta</first>
207-
<last>Xie</last>
208-
</name>
209-
201+
```xml
202+
FirstName string `xml:"name>first"`
203+
LastName string `xml:"name>last"`
204+
205+
<name>
206+
<first>Asta</first>
207+
<last>Xie</last>
208+
</name>
209+
```
210210
You may have noticed that struct tags are very useful for dealing with XML, and the same goes for the other data formats we'll be discussing in the following sections. If you still find that you have problems with working with struct tags, you should probably read more documentation about them before diving into the next section.
211211

212212
## Links

0 commit comments

Comments
 (0)