1. 程式人生 > 實用技巧 >golang學習筆記---encoding/xml

golang學習筆記---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 information 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 information 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 寫入到流裡面。