diff --git a/en/07.1.md b/en/07.1.md
index 599e40ea..17fe147c 100644
--- a/en/07.1.md
+++ b/en/07.1.md
@@ -6,17 +6,17 @@ I will not make any attempts to teach XML's syntax or conventions. For that, ple
Suppose you work in IT, and you have to deal with the following XML configuration file:
```xml
-
-
-
- Shanghai_VPN
- 127.0.0.1
-
-
- Beijing_VPN
- 127.0.0.2
-
-
+
+
+
+ Shanghai_VPN
+ 127.0.0.1
+
+
+ Beijing_VPN
+ 127.0.0.2
+
+
```
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.
@@ -30,66 +30,66 @@ the `data` parameter receives a data stream from an XML source, and `v` is the s
Sample code:
```Go
- package main
-
- import (
- "encoding/xml"
- "fmt"
- "io/ioutil"
- "os"
- )
-
- type Recurlyservers struct {
- XMLName xml.Name `xml:"servers"`
- Version string `xml:"version,attr"`
- Svs []server `xml:"server"`
- Description string `xml:",innerxml"`
- }
-
- type server struct {
- XMLName xml.Name `xml:"server"`
- ServerName string `xml:"serverName"`
- ServerIP string `xml:"serverIP"`
- }
-
- func main() {
- file, err := os.Open("servers.xml") // For read access.
- if err != nil {
- fmt.Printf("error: %v", err)
- return
- }
- defer file.Close()
- data, err := ioutil.ReadAll(file)
- if err != nil {
- fmt.Printf("error: %v", err)
- return
- }
- v := Recurlyservers{}
- err = xml.Unmarshal(data, &v)
- if err != nil {
- fmt.Printf("error: %v", err)
- return
- }
-
- fmt.Println(v)
- }
+package main
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+
+type Recurlyservers struct {
+ XMLName xml.Name `xml:"servers"`
+ Version string `xml:"version,attr"`
+ Svs []server `xml:"server"`
+ Description string `xml:",innerxml"`
+}
+
+type server struct {
+ XMLName xml.Name `xml:"server"`
+ ServerName string `xml:"serverName"`
+ ServerIP string `xml:"serverIP"`
+}
+
+func main() {
+ file, err := os.Open("servers.xml") // For read access.
+ if err != nil {
+ fmt.Printf("error: %v", err)
+ return
+ }
+ defer file.Close()
+ data, err := ioutil.ReadAll(file)
+ if err != nil {
+ fmt.Printf("error: %v", err)
+ return
+ }
+ v := Recurlyservers{}
+ err = xml.Unmarshal(data, &v)
+ if err != nil {
+ fmt.Printf("error: %v", err)
+ return
+ }
+
+ fmt.Println(v)
+}
```
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:
```xml
- {{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
-
- Shanghai_VPN
- 127.0.0.1
-
-
- Beijing_VPN
- 127.0.0.2
-
- }
+{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
+
+ Shanghai_VPN
+ 127.0.0.1
+
+
+ Beijing_VPN
+ 127.0.0.2
+
+}
```
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:
```Go
- func Unmarshal(data []byte, v interface{}) error
+func Unmarshal(data []byte, v interface{}) error
```
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.
@@ -117,58 +117,58 @@ Note that all fields in structs should be exported (capitalized) in order to par
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:
```Go
- func Marshal(v interface{}) ([]byte, error)
- func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
+func Marshal(v interface{}) ([]byte, error)
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
```
The first argument in both of these functions is for storing a marshalled XML data stream.
Let's look at an example to see how this works:
```Go
- package main
-
- import (
- "encoding/xml"
- "fmt"
- "os"
- )
-
- type Servers struct {
- XMLName xml.Name `xml:"servers"`
- Version string `xml:"version,attr"`
- 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"})
- output, err := xml.MarshalIndent(v, " ", " ")
- if err != nil {
- fmt.Printf("error: %v\n", err)
- }
- os.Stdout.Write([]byte(xml.Header))
-
- os.Stdout.Write(output)
- }
+package main
+
+import (
+ "encoding/xml"
+ "fmt"
+ "os"
+)
+
+type Servers struct {
+ XMLName xml.Name `xml:"servers"`
+ Version string `xml:"version,attr"`
+ 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"})
+ output, err := xml.MarshalIndent(v, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", err)
+ }
+ os.Stdout.Write([]byte(xml.Header))
+
+ os.Stdout.Write(output)
+}
```
The above example prints the following information:
```xml
-
-
-
- Shanghai_VPN
- 127.0.0.1
-
-
- Beijing_VPN
- 127.0.0.2
-
-
+
+
+
+ Shanghai_VPN
+ 127.0.0.1
+
+
+ Beijing_VPN
+ 127.0.0.2
+
+
```
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.
@@ -199,13 +199,13 @@ Then we need to figure out how to set tags in order to produce the final XML doc
- 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.
- If a tag contains `"a>b>c"`, it prints three elements where a contains b and b contains c, like in the following code:
```xml
- FirstName string `xml:"name>first"`
- LastName string `xml:"name>last"`
-
-
- Asta
- Xie
-
+FirstName string `xml:"name>first"`
+LastName string `xml:"name>last"`
+
+
+Asta
+Xie
+
```
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.