Golang標(biāo)準(zhǔn)庫(kù)——encoding(3)

  • json
  • pem
  • xml

json

json包實(shí)現(xiàn)了json對(duì)象的編解碼,參見RFC 4627。Json對(duì)象和go類型的映射關(guān)系請(qǐng)參見Marshal和Unmarshal函數(shù)的文檔。

參見"JSON and Go"獲取本包的一個(gè)介紹:http://golang.org/doc/articles/json_and_go.html

type InvalidUTF8Error

type InvalidUTF8Error struct {
    S string // 引發(fā)錯(cuò)誤的完整字符串
}

Go 1.2之前版本,當(dāng)試圖編碼一個(gè)包含非法utf-8序列的字符串時(shí)會(huì)返回本錯(cuò)誤。Go 1.2及之后版本,編碼器會(huì)強(qiáng)行將非法字節(jié)替換為unicode字符U+FFFD來使字符串合法。本錯(cuò)誤已不會(huì)再出現(xiàn),但出于向后兼容考慮而保留。

func (*InvalidUTF8Error) Error

func (e *InvalidUTF8Error) Error() string

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
    Type reflect.Type
}

InvalidUnmarshalError用于描述一個(gè)傳遞給解碼器的非法參數(shù)。(解碼器的參數(shù)必須是非nil指針)

func (*InvalidUnmarshalError) Error

func (e *InvalidUnmarshalError) Error() string

type SyntaxError

type SyntaxError struct {
    msg    string // description of error
    Offset int64  // error occurred after reading Offset bytes
}

SyntaxError表示一個(gè)json語法錯(cuò)誤。

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type UnmarshalFieldError

type UnmarshalFieldError struct {
    Key   string
    Type  reflect.Type
    Field reflect.StructField
}

UnmarshalFieldError表示一個(gè)json對(duì)象的鍵指向一個(gè)非導(dǎo)出字段。(因此不能寫入;已不再使用,出于兼容保留)

func (*UnmarshalFieldError) Error

func (e *UnmarshalFieldError) Error() string

type UnmarshalTypeError

type UnmarshalTypeError struct {
    Value string       // 描述json值:"bool", "array", "number -5"
    Type  reflect.Type // 不能轉(zhuǎn)化為的go類型
}

UnmarshalTypeError表示一個(gè)json值不能轉(zhuǎn)化為特定的go類型的值。

func (*UnmarshalTypeError) Error

func (e *UnmarshalTypeError) Error() string

type UnsupportedTypeError

type UnsupportedTypeError struct {
    Type reflect.Type
}

UnsupportedTypeError表示試圖編碼一個(gè)不支持類型的值。

func (*UnsupportedTypeError) Error

func (e *UnsupportedTypeError) Error() string

type UnsupportedValueError

type UnsupportedValueError struct {
    Value reflect.Value
    Str   string
}

func (*UnsupportedValueError) Error

func (e *UnsupportedValueError) Error() string

type MarshalerError

type MarshalerError struct {
    Type reflect.Type
    Err  error
}

func (*MarshalerError) Error

func (e *MarshalerError) Error() string

type Number

type Number string

Number類型代表一個(gè)json數(shù)字字面量。

func (Number) Int64

func (n Number) Int64() (int64, error)

將該數(shù)字作為int64類型返回。

func (Number) Float64

func (n Number) Float64() (float64, error)

將該數(shù)字作為float64類型返回。

func (Number) String

func (n Number) String() string

返回該數(shù)字的字面值文本表示。

type RawMessage

type RawMessage []byte

RawMessage類型是一個(gè)保持原本編碼的json對(duì)象。本類型實(shí)現(xiàn)了Marshaler和Unmarshaler接口,用于延遲json的解碼或者預(yù)計(jì)算json的編碼。

type Color struct {
    Space string
    Point json.RawMessage // delay parsing until we know the color space
}
type RGB struct {
    R uint8
    G uint8
    B uint8
}
type YCbCr struct {
    Y  uint8
    Cb int8
    Cr int8
}

func main() {
    var j = []byte(`[
        {"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
        {"Space": "RGB",   "Point": {"R": 98, "G": 218, "B": 255}}
    ]`)
    var colors []Color
    err := json.Unmarshal(j, &colors)
    if err != nil {
        log.Fatalln("error:", err)
    }
    for _, c := range colors {
        var dst interface{}
        switch c.Space {
        case "RGB":
            dst = new(RGB)
        case "YCbCr":
            dst = new(YCbCr)
        }
        err := json.Unmarshal(c.Point, dst)
        if err != nil {
            log.Fatalln("error:", err)
        }
        fmt.Println(c.Space, dst)
    }
}

func (*RawMessage) MarshalJSON

func (m *RawMessage) MarshalJSON() ([]byte, error)

MarshalJSON返回*m的json編碼。

func (*RawMessage) UnmarshalJSON

func (m *RawMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON將*m設(shè)為data的一個(gè)拷貝。

type Marshaler

type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

實(shí)現(xiàn)了Marshaler接口的類型可以將自身序列化為合法的json描述。

type Unmarshaler

type Unmarshaler interface {
    UnmarshalJSON([]byte) error
}

實(shí)現(xiàn)了Unmarshaler接口的對(duì)象可以將自身的json描述反序列化。該方法可以認(rèn)為輸入是合法的json字符串。如果要在方法返回后保存自身的json數(shù)據(jù),必須進(jìn)行拷貝。

func Compact

func Compact(dst *bytes.Buffer, src []byte) error

Compact函數(shù)將json編碼的src中無用的空白字符剔除后寫入dst。

func HTMLEscape

func HTMLEscape(dst *bytes.Buffer, src []byte)

HTMLEscape 函數(shù)將json編碼的src中的<、>、&、U+2028 和U+2029字符替換為\u003c、\u003e、\u0026、\u2028、\u2029 轉(zhuǎn)義字符串,以便json編碼可以安全的嵌入HTML的<script>標(biāo)簽里。因?yàn)闅v史原因,網(wǎng)絡(luò)瀏覽器不支持在<script>標(biāo)簽中使用標(biāo)準(zhǔn)HTML轉(zhuǎn)義, 因此必須使用另一種json編碼方案。

func Indent

func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error

Indent函數(shù)將json編碼的調(diào)整縮進(jìn)之后寫入dst。每一個(gè)json元素/數(shù)組都另起一行開始,以prefix為起始,一或多個(gè)indent縮進(jìn)(數(shù)目看嵌套層數(shù))。寫入dst的數(shù)據(jù)起始沒有prefix字符,也沒有indent字符,最后也不換行,因此可以更好的嵌入其他格式化后的json數(shù)據(jù)里。

type Road struct {
    Name   string
    Number int
}

func main() {
    roads := []Road{
        {"Diamond Fork", 29},
        {"Sheep Creek", 51},
    }
    b, err := json.Marshal(roads)
    if err != nil {
        log.Fatal(err)
    }
    var out bytes.Buffer
    json.Indent(&out, b, "=", "\t")
    out.WriteTo(os.Stdout)
}

func Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal函數(shù)返回v的json編碼。

Marshal函數(shù)會(huì)遞歸的處理值。如果一個(gè)值實(shí)現(xiàn)了Marshaler接口切非nil指針,會(huì)調(diào)用其MarshalJSON方法來生成json編碼。nil指針異常并不是嚴(yán)格必需的,但會(huì)模擬與UnmarshalJSON的行為類似的必需的異常。

否則,Marshal函數(shù)使用下面的基于類型的默認(rèn)編碼格式:

布爾類型編碼為json布爾類型。

浮點(diǎn)數(shù)、整數(shù)和Number類型的值編碼為json數(shù)字類型。

字符串編碼為json字符串。角括號(hào)"<"和">"會(huì)轉(zhuǎn)義為"\u003c"和"\u003e"以避免某些瀏覽器吧json輸出錯(cuò)誤理解為HTML?;谕瑯拥脑?,"&"轉(zhuǎn)義為"\u0026"。

數(shù)組和切片類型的值編碼為json數(shù)組,但[]byte編碼為base64編碼字符串,nil切片編碼為null。

結(jié)構(gòu)體的值編碼為json對(duì)象。每一個(gè)導(dǎo)出字段變成該對(duì)象的一個(gè)成員,除非:

- 字段的標(biāo)簽是"-"
- 字段是空值,而其標(biāo)簽指定了omitempty選項(xiàng)

空值是false、0、""、nil指針、nil接口、長(zhǎng)度為0的數(shù)組、切片、映射。對(duì)象默認(rèn)鍵字符串是結(jié)構(gòu)體的字段名,但可以在結(jié)構(gòu)體字段的標(biāo)簽里指定。結(jié)構(gòu)體標(biāo)簽值里的"json"鍵為鍵名,后跟可選的逗號(hào)和選項(xiàng),舉例如下:

// 字段被本包忽略
Field int `json:"-"`
// 字段在json里的鍵為"myName"
Field int `json:"myName"`
// 字段在json里的鍵為"myName"且如果字段為空值將在對(duì)象中省略掉
Field int `json:"myName,omitempty"`
// 字段在json里的鍵為"Field"(默認(rèn)值),但如果字段為空值會(huì)跳過;注意前導(dǎo)的逗號(hào)
Field int `json:",omitempty"`

"string"選項(xiàng)標(biāo)記一個(gè)字段在編碼json時(shí)應(yīng)編碼為字符串。它只適用于字符串、浮點(diǎn)數(shù)、整數(shù)類型的字段。這個(gè)額外水平的編碼選項(xiàng)有時(shí)候會(huì)用于和javascript程序交互:

Int64String int64 `json:",string"`

如果鍵名是只含有unicode字符、數(shù)字、美元符號(hào)、百分號(hào)、連字符、下劃線和斜杠的非空字符串,將使用它代替字段名。

匿名的結(jié)構(gòu)體字段一般序列化為他們內(nèi)部的導(dǎo)出字段就好像位于外層結(jié)構(gòu)體中一樣。如果一個(gè)匿名結(jié)構(gòu)體字段的標(biāo)簽給其提供了鍵名,則會(huì)使用鍵名代替字段名,而不視為匿名。

Go結(jié)構(gòu)體字段的可視性規(guī)則用于供json決定那個(gè)字段應(yīng)該序列化或反序列化時(shí)是經(jīng)過修正了的。如果同一層次有多個(gè)(匿名)字段且該層次是最小嵌套的(嵌套層次則使用默認(rèn)go規(guī)則),會(huì)應(yīng)用如下額外規(guī)則:

1)json標(biāo)簽為"-"的匿名字段強(qiáng)行忽略,不作考慮;

2)json標(biāo)簽提供了鍵名的匿名字段,視為非匿名字段;

3)其余字段中如果只有一個(gè)匿名字段,則使用該字段;

4)其余字段中如果有多個(gè)匿名字段,但壓平后不會(huì)出現(xiàn)沖突,所有匿名字段壓平;

5)其余字段中如果有多個(gè)匿名字段,但壓平后出現(xiàn)沖突,全部忽略,不產(chǎn)生錯(cuò)誤。

對(duì)匿名結(jié)構(gòu)體字段的管理是從go1.1開始的,在之前的版本,匿名字段會(huì)直接忽略掉。

映射類型的值編碼為json對(duì)象。映射的鍵必須是字符串,對(duì)象的鍵直接使用映射的鍵。

指針類型的值編碼為其指向的值(的json編碼)。nil指針編碼為null。

接口類型的值編碼為接口內(nèi)保持的具體類型的值(的json編碼)。nil接口編碼為null。

通道、復(fù)數(shù)、函數(shù)類型的值不能編碼進(jìn)json。嘗試編碼它們會(huì)導(dǎo)致Marshal函數(shù)返回UnsupportedTypeError。

Json不能表示循環(huán)的數(shù)據(jù)結(jié)構(gòu),將一個(gè)循環(huán)的結(jié)構(gòu)提供給Marshal函數(shù)會(huì)導(dǎo)致無休止的循環(huán)。

type ColorGroup struct {
    ID     int
    Name   string
    Colors []string
}
func main() {
    group := ColorGroup{
        ID:     1,
        Name:   "Reds",
        Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
    }
    b, err := json.Marshal(group)
    if err != nil {
        fmt.Println("error:", err)
    }
    os.Stdout.Write(b)
}

func MarshalIndent

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

MarshalIndent類似Marshal但會(huì)使用縮進(jìn)將輸出格式化。

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal函數(shù)解析json編碼的數(shù)據(jù)并將結(jié)果存入v指向的值。

Unmarshal和Marshal做相反的操作,必要時(shí)申請(qǐng)映射、切片或指針,有如下的附加規(guī)則:

要將json數(shù)據(jù)解碼寫入一個(gè)指針,Unmarshal函數(shù)首先處理json數(shù)據(jù)是json字面值null的情況。此時(shí),函數(shù)將指針設(shè)為nil;否則,函數(shù)將json數(shù)據(jù)解碼寫入指針指向的值;如果指針本身是nil,函數(shù)會(huì)先申請(qǐng)一個(gè)值并使指針指向它。

要將json數(shù)據(jù)解碼寫入一個(gè)結(jié)構(gòu)體,函數(shù)會(huì)匹配輸入對(duì)象的鍵和Marshal使用的鍵(結(jié)構(gòu)體字段名或者它的標(biāo)簽指定的鍵名),優(yōu)先選擇精確的匹配,但也接受大小寫不敏感的匹配。

要將json數(shù)據(jù)解碼寫入一個(gè)接口類型值,函數(shù)會(huì)將數(shù)據(jù)解碼為如下類型寫入接口:

Bool                   對(duì)應(yīng)JSON布爾類型
float64                對(duì)應(yīng)JSON數(shù)字類型
string                 對(duì)應(yīng)JSON字符串類型
[]interface{}          對(duì)應(yīng)JSON數(shù)組
map[string]interface{} 對(duì)應(yīng)JSON對(duì)象
nil                    對(duì)應(yīng)JSON的null

如果一個(gè)JSON值不匹配給出的目標(biāo)類型,或者如果一個(gè)json數(shù)字寫入目標(biāo)類型時(shí)溢出,Unmarshal函數(shù)會(huì)跳過該字段并盡量完成其余的解碼操作。如果沒有出現(xiàn)更加嚴(yán)重的錯(cuò)誤,本函數(shù)會(huì)返回一個(gè)描述第一個(gè)此類錯(cuò)誤的詳細(xì)信息的UnmarshalTypeError。

JSON的null值解碼為go的接口、指針、切片時(shí)會(huì)將它們?cè)O(shè)為nil,因?yàn)閚ull在json里一般表示“不存在”。 解碼json的null值到其他go類型時(shí),不會(huì)造成任何改變,也不會(huì)產(chǎn)生錯(cuò)誤。
當(dāng)解碼字符串時(shí),不合法的utf-8或utf-16代理(字符)對(duì)不視為錯(cuò)誤,而是將非法字符替換為unicode字符U+FFFD。

func main() {
    var jsonBlob = []byte(`[
        {"Name": "Platypus", "Order": "Monotremata"},
        {"Name": "Quoll",    "Order": "Dasyuromorphia"}
    ]`)
    type Animal struct {
        Name  string
        Order string
    }
    var animals []Animal
    err := json.Unmarshal(jsonBlob, &animals)
    if err != nil {
        fmt.Println("error:", err)
    }
    fmt.Printf("%+v", animals)
}

type Decoder

type Decoder struct {
    r       io.Reader
    buf     []byte
    d       decodeState
    scanp   int   // start of unread data in buf
    scanned int64 // amount of data already scanned
    scan    scanner
    err     error

    tokenState int
    tokenStack []int
}

Decoder從輸入流解碼json對(duì)象

func main() {
    const jsonStream = `
        {"Name": "Ed", "Text": "Knock knock."}
        {"Name": "Sam", "Text": "Who's there?"}
        {"Name": "Ed", "Text": "Go fmt."}
        {"Name": "Sam", "Text": "Go fmt who?"}
        {"Name": "Ed", "Text": "Go fmt yourself!"}
    `
    type Message struct {
        Name, Text string
    }
    dec := json.NewDecoder(strings.NewReader(jsonStream))
    for {
        var m Message
        if err := dec.Decode(&m); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s: %s\n", m.Name, m.Text)
    }
}

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder創(chuàng)建一個(gè)從r讀取并解碼json對(duì)象的*Decoder,解碼器有自己的緩沖,并可能超前讀取部分json數(shù)據(jù)。

func (*Decoder) Buffered

func (dec *Decoder) Buffered() io.Reader

Buffered方法返回保存在dec緩存里數(shù)據(jù)的讀取器,該返回值在下次調(diào)用Decode方法之前有效。

func (*Decoder) UseNumber

func (dec *Decoder) UseNumber()

UseNumber方法將dec設(shè)置為當(dāng)接收端是interface{}接口時(shí)將json數(shù)字解碼為Number類型而不是float64類型

func (*Decoder) Decode

func (dec *Decoder) Decode(v interface{}) error

Decode從輸入流讀取下一個(gè)json編碼值并保存在v指向的值里,參見Unmarshal函數(shù)的文檔獲取細(xì)節(jié)信息。

type Encoder

type Encoder struct {
    w          io.Writer
    err        error
    escapeHTML bool

    indentBuf    *bytes.Buffer
    indentPrefix string
    indentValue  string
}

Encoder將json對(duì)象寫入輸出流。

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder創(chuàng)建一個(gè)將數(shù)據(jù)寫入w的*Encoder。

func (*Encoder) Encode

func (enc *Encoder) Encode(v interface{}) error

Encode將v的json編碼寫入輸出流,并會(huì)寫入一個(gè)換行符,參見Marshal函數(shù)的文檔獲取細(xì)節(jié)信息。

pem

pem包實(shí)現(xiàn)了PEM數(shù)據(jù)編碼(源自保密增強(qiáng)郵件協(xié)議)。目前PEM編碼主要用于TLS密鑰和證書。參見RFC 1421

type Block

type Block struct {
    Type    string            // 得自前言的類型(如"RSA PRIVATE KEY")
    Headers map[string]string // 可選的頭項(xiàng)
    Bytes   []byte            // 內(nèi)容解碼后的數(shù)據(jù),一般是DER編碼的ASN.1結(jié)構(gòu)
}

Block代表PEM編碼的結(jié)構(gòu)。編碼格式如下:

-----BEGIN Type-----
Headers
base64-encoded Bytes
-----END Type-----

其中Headers是可為空的多行鍵值對(duì)。

func Decode

func Decode(data []byte) (p *Block, rest []byte)

Decode函數(shù)會(huì)從輸入里查找到下一個(gè)PEM格式的塊(證書、私鑰等)。它返回解碼得到的Block和剩余未解碼的數(shù)據(jù)。如果未發(fā)現(xiàn)PEM數(shù)據(jù),返回(nil, data)。

func Encode

func Encode(out io.Writer, b *Block) error

func EncodeToMemory

func EncodeToMemory(b *Block) []byte

xml

xml包實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的XML 1.0解析器,該解析器可以理解XML名稱空間。

Constants

const (
    // 適用于本包Marshal輸出的一般性XML header
    // 本常數(shù)并不會(huì)自動(dòng)添加到本包的輸出里,這里提供主要是出于便利的目的
    Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
)

Variables

var HTMLAutoClose = htmlAutoClose

HTMLAutoClose是應(yīng)當(dāng)考慮到自動(dòng)關(guān)閉的HTML元素的集合。

var HTMLEntity = htmlEntity

HTMLEntity是標(biāo)準(zhǔn)HTML entity字符到其翻譯的映射。

type SyntaxError

type SyntaxError struct {
    Msg  string
    Line int
}

SyntaxError代表XML輸入流的格式錯(cuò)誤。

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type TagPathError

type TagPathError struct {
    Struct       reflect.Type
    Field1, Tag1 string
    Field2, Tag2 string
}

反序列化時(shí),如果字段標(biāo)簽的路徑有沖突,就會(huì)返回TagPathError。

func (*TagPathError) Error

func (e *TagPathError) Error() string

type UnsupportedTypeError

type UnsupportedTypeError struct {
    Type reflect.Type
}

當(dāng)序列化時(shí),如果遇到不能轉(zhuǎn)化為XML的類型,就會(huì)返回UnsupportedTypeError。

func (*UnsupportedTypeError) Error

func (e *UnsupportedTypeError) Error() string

type UnmarshalError

type UnmarshalError string

UnmarshalError代表反序列化時(shí)出現(xiàn)的錯(cuò)誤。

func (UnmarshalError) Error

func (e UnmarshalError) Error() string

type CharData

type CharData []byte

CharData類型代表XML字符數(shù)據(jù)(原始文本),其中XML轉(zhuǎn)義序列已經(jīng)被它們所代表的字符取代。

func (CharData) Copy

func (c CharData) Copy() CharData

type Comment

type Comment []byte

Comment代表XML注釋,格式為,切片中不包含注釋標(biāo)記<!—和-->。

func (Comment) Copy

func (c Comment) Copy() Comment

type Directive

type Directive []byte

Directive代表XML指示,格式為<!directive>,切片中不包含標(biāo)記<!和>。

func (Directive) Copy

func (d Directive) Copy() Directive

type ProcInst

type ProcInst struct {
    Target string
    Inst   []byte
}

ProcInst代表XML處理指令,格式為<?target inst?>。

func (ProcInst) Copy

func (p ProcInst) Copy() ProcInst

type Name

type Name struct {
    Space, Local string
}

Name代表一個(gè)XML名稱(Local字段),并指定名字空間(Space)。Decoder.Token方法返回的Token中,Space標(biāo)識(shí)符是典型的URL而不是被解析的文檔里的短前綴。

type Attr

type Attr struct {
    Name  Name
    Value string
}

Attr代表一個(gè)XML元素的一條屬性(Name=Value)

type StartElement

type StartElement struct {
    Name Name
    Attr []Attr
}

StartElement代表一個(gè)XML起始元素。

func (StartElement) Copy

func (e StartElement) Copy() StartElement

func (StartElement) End

func (e StartElement) End() EndElement

返回e對(duì)應(yīng)的XML結(jié)束元素。

type EndElement

type EndElement struct {
    Name Name
}

EndElement代表一個(gè)XML結(jié)束元素。

type Token

type Token interface{}

Token接口用于保存token類型(CharData、Comment、Directive、ProcInst、StartElement、EndElement)的值。

func CopyToken

func CopyToken(t Token) Token

CopyToken返回一個(gè)Token的拷貝。

type Marshaler

type Marshaler interface {
    MarshalXML(e *Encoder, start StartElement) error
}

實(shí)現(xiàn)了Marshaler接口的類型可以將自身序列化為合法的XML元素。

MarshalXML方法將自身調(diào)用者編碼為零或多個(gè)XML元素。 按照慣例,數(shù)組或切片會(huì)編碼為一系列元素,每個(gè)成員一條。使用start作為元素標(biāo)簽并不是必須的,但這么做可以幫助Unmarshal方法正確的匹配XML元素和結(jié)構(gòu)體字段。一個(gè)常用的策略是在同一個(gè)層次里將每個(gè)獨(dú)立的值對(duì)應(yīng)到期望的XML然后使用e.EncodeElement進(jìn)行編碼。另一個(gè)常用的策略是重復(fù)調(diào)用e.EncodeToken來一次一個(gè)token的生成XML輸出。編碼后的token必須組成零或多個(gè)XML元素。

type Unmarshaler

type Unmarshaler interface {
    UnmarshalXML(d *Decoder, start StartElement) error
}

實(shí)現(xiàn)了Unmarshaler接口的類型可以根據(jù)自身的XML元素描述反序列化自身。

UnmarshalXML方法解碼以start起始單個(gè)XML元素。如果它返回了錯(cuò)誤,外層Unmarshal的調(diào)用將停止執(zhí)行并返回該錯(cuò)誤。UnmarshalXML方法必須正好“消費(fèi)”一個(gè)XML元素。一個(gè)常用的策略是使用d.DecodeElement 將XML分別解碼到各獨(dú)立值,然后再將這些值寫入U(xiǎn)nmarshalXML的調(diào)用者。另一個(gè)常用的策略是使用d.Token一次一個(gè)token的處理XML對(duì)象。UnmarshalXML通常不使用d.RawToken。

type MarshalerAttr

type MarshalerAttr interface {
    MarshalXMLAttr(name Name) (Attr, error)
}

實(shí)現(xiàn)了MarshalerAttr接口的類型可以將自身序列化為合法的XML屬性。

MarshalXMLAttr返回一個(gè)值為方法調(diào)用者編碼后的值的XML屬性。使用name作為屬性的name并非必須的,但這么做可以幫助Unmarshal方法正確的匹配屬性和結(jié)構(gòu)體字段。如果MarshalXMLAttr返回一個(gè)零值屬性Attr{},將不會(huì)生成屬性輸出。MarshalXMLAttr只用于有標(biāo)簽且標(biāo)簽有"attr"選項(xiàng)的結(jié)構(gòu)體字段。

type UnmarshalerAttr

type UnmarshalerAttr interface {
    UnmarshalXMLAttr(attr Attr) error
}

實(shí)現(xiàn)了UnmarshalerAttr接口的類型可以根據(jù)自身的XML屬性形式的描述反序列化自身。

UnmarshalXMLAttr解碼單個(gè)的XML屬性。如果它返回一個(gè)錯(cuò)誤,外層的Umarshal調(diào)用會(huì)停止執(zhí)行并返回該錯(cuò)誤。UnmarshalXMLAttr只有在結(jié)構(gòu)體字段的標(biāo)簽有"attr"選項(xiàng)時(shí)才被使用。

func Escape

func Escape(w io.Writer, s []byte)

Escape類似EscapeText函數(shù)但會(huì)忽略返回的錯(cuò)誤。本函數(shù)是用于保證和Go 1.0的向后兼容。應(yīng)用于Go 1.1及以后版本的代碼請(qǐng)使用EscapeText。

func EscapeText

func EscapeText(w io.Writer, s []byte) error

EscapeText向w中寫入經(jīng)過適當(dāng)轉(zhuǎn)義的、有明文s具有相同意義的XML文本。

func Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal函數(shù)返回v的XML編碼。

Marshal處理數(shù)組或者切片時(shí)會(huì)序列化每一個(gè)元素。Marshal處理指針時(shí),會(huì)序列化其指向的值;如果指針為nil,則啥也不輸出。Marshal處理接口時(shí),會(huì)序列化其內(nèi)包含的具體類型值,如果接口值為nil,也是不輸出。Marshal處理其余類型數(shù)據(jù)時(shí),會(huì)輸出一或多個(gè)包含數(shù)據(jù)的XML元素。

XML元素的名字按如下優(yōu)先順序獲取:

- 如果數(shù)據(jù)是結(jié)構(gòu)體,其XMLName字段的標(biāo)簽
- 類型為xml.Name的XMLName字段的值
- 數(shù)據(jù)是某結(jié)構(gòu)體的字段,其標(biāo)簽
- 數(shù)據(jù)是某結(jié)構(gòu)體的字段,其字段名
- 被序列化的類型的名字

一個(gè)結(jié)構(gòu)體的XML元素包含該結(jié)構(gòu)體所有導(dǎo)出字段序列化后的元素,有如下例外:

- XMLName字段,如上所述,會(huì)省略
- 具有標(biāo)簽"-"的字段會(huì)省略
- 具有標(biāo)簽"name,attr"的字段會(huì)成為該XML元素的名為name的屬性
- 具有標(biāo)簽",attr"的字段會(huì)成為該XML元素的名為字段名的屬性
- 具有標(biāo)簽",chardata"的字段會(huì)作為字符數(shù)據(jù)寫入,而非XML元素
- 具有標(biāo)簽",innerxml"的字段會(huì)原樣寫入,而不會(huì)經(jīng)過正常的序列化過程
- 具有標(biāo)簽",comment"的字段作為XML注釋寫入,而不經(jīng)過正常的序列化過程,該字段內(nèi)不能有"--"字符串
- 標(biāo)簽中包含"omitempty"選項(xiàng)的字段如果為空值會(huì)省略
  空值為false、0、nil指針、nil接口、長(zhǎng)度為0的數(shù)組、切片、映射
- 匿名字段(其標(biāo)簽無效)會(huì)被處理為其字段是外層結(jié)構(gòu)體的字段

如果一個(gè)字段的標(biāo)簽為"a>b>c",則元素c將會(huì)嵌套進(jìn)其上層元素a和b中。如果該字段相鄰的字段標(biāo)簽指定了同樣的上層元素,則會(huì)放在同一個(gè)XML元素里。

參見MarshalIndent的例子。如果要求Marshal序列化通道、函數(shù)或者映射會(huì)返回錯(cuò)誤。

func MarshalIndent

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

MarshalIndent功能類似Marshal。但每個(gè)XML元素會(huì)另起一行并縮進(jìn),該行以prefix起始,后跟一或多個(gè)indent的拷貝(根據(jù)嵌套層數(shù))。

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"`
}
func main() {

    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)
}

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal解析XML編碼的數(shù)據(jù)并將結(jié)果存入v指向的值。v只能指向結(jié)構(gòu)體、切片或者和字符串。良好格式化的數(shù)據(jù)如果不能存入v,會(huì)被丟棄。

因?yàn)閁nmarshal使用reflect包,它只能填寫導(dǎo)出字段。本函數(shù)好似用大小寫敏感的比較來匹配XML元素名和結(jié)構(gòu)體的字段名/標(biāo)簽鍵名。

Unmarshal函數(shù)使用如下規(guī)則將XML元素映射到結(jié)構(gòu)體字段上。這些規(guī)則中,字段標(biāo)簽指的是結(jié)構(gòu)體字段的標(biāo)簽鍵'xml'對(duì)應(yīng)的值(參見上面的例子):

* 如果結(jié)構(gòu)體字段的類型為字符串或者[]byte,且標(biāo)簽為",innerxml",
  Unmarshal函數(shù)直接將對(duì)應(yīng)原始XML文本寫入該字段,其余規(guī)則仍適用。
* 如果結(jié)構(gòu)體字段類型為xml.Name且名為XMLName,Unmarshal會(huì)將元素名寫入該字段
* 如果字段XMLName的標(biāo)簽的格式為"name"或"namespace-URL name",
  XML元素必須有給定的名字(以及可選的名字空間),否則Unmarshal會(huì)返回錯(cuò)誤。
* 如果XML元素的屬性的名字匹配某個(gè)標(biāo)簽",attr"為字段的字段名,或者匹配某個(gè)標(biāo)簽為"name,attr"
  的字段的標(biāo)簽名,Unmarshal會(huì)將該屬性的值寫入該字段。
* 如果XML元素包含字符數(shù)據(jù),該數(shù)據(jù)會(huì)存入結(jié)構(gòu)體中第一個(gè)具有標(biāo)簽",chardata"的字段中,
  該字段可以是字符串類型或者[]byte類型。如果沒有這樣的字段,字符數(shù)據(jù)會(huì)丟棄。
* 如果XML元素包含注釋,該數(shù)據(jù)會(huì)存入結(jié)構(gòu)體中第一個(gè)具有標(biāo)簽",comment"的字段中,
  該字段可以是字符串類型或者[]byte類型。如果沒有這樣的字段,字符數(shù)據(jù)會(huì)丟棄。
* 如果XML元素包含一個(gè)子元素,其名稱匹配格式為"a"或"a>b>c"的標(biāo)簽的前綴,反序列化會(huì)深入
  XML結(jié)構(gòu)中尋找具有指定名稱的元素,并將最后端的元素映射到該標(biāo)簽所在的結(jié)構(gòu)體字段。
  以">"開始的標(biāo)簽等價(jià)于以字段名開始并緊跟著">" 的標(biāo)簽。
* 如果XML元素包含一個(gè)子元素,其名稱匹配某個(gè)結(jié)構(gòu)體類型字段的XMLName字段的標(biāo)簽名,
  且該結(jié)構(gòu)體字段本身沒有顯式指定標(biāo)簽名,Unmarshal會(huì)將該元素映射到該字段。
* 如果XML元素的包含一個(gè)子元素,其名稱匹配夠格結(jié)構(gòu)體字段的字段名,且該字段沒有任何模式選項(xiàng)
  (",attr"、",chardata"等),Unmarshal會(huì)將該元素映射到該字段。
* 如果XML元素包含的某個(gè)子元素不匹配以上任一條,而存在某個(gè)字段其標(biāo)簽為",any",
  Unmarshal會(huì)將該元素映射到該字段。
* 匿名字段被處理為其字段好像位于外層結(jié)構(gòu)體中一樣。
* 標(biāo)簽為"-"的結(jié)構(gòu)體字段永不會(huì)被反序列化填寫。

Unmarshal函數(shù)將XML元素寫入string或[]byte時(shí),會(huì)將該元素的字符數(shù)據(jù)串聯(lián)起來作為值,目標(biāo)[]byte不能是nil。

Unmarshal函數(shù)將屬性寫入string或[]byte時(shí),會(huì)將屬性的值以字符串/切片形式寫入。

Unmarshal函數(shù)將XML元素寫入切片時(shí),會(huì)將切片擴(kuò)展并將XML元素的子元素映射入新建的值里。

Unmarshal函數(shù)將XML元素/屬性寫入bool值時(shí),會(huì)將對(duì)應(yīng)的字符串轉(zhuǎn)化為布爾值。

Unmarshal函數(shù)將XML元素/屬性寫入整數(shù)或浮點(diǎn)數(shù)類型時(shí),會(huì)將對(duì)應(yīng)的字符串解釋為十進(jìn)制數(shù)字。不會(huì)檢查溢出。

Unmarshal函數(shù)將XML元素寫入xml.Name類型時(shí),會(huì)記錄元素的名稱。

Unmarshal函數(shù)將XML元素寫入指針時(shí),會(huì)申請(qǐng)一個(gè)新值并將XML元素映射入該值。

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
}
func main() {


    v := Result{Name: "none", Phone: "none"}
    data := `
        <Person>
            <FullName>Grace R. Emlin</FullName>
            <Company>Example Inc.</Company>
            <Email where="home">
                <Addr>gre@example.com</Addr>
            </Email>
            <Email where='work'>
                <Addr>gre@work.com</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)
}

type Decoder

type Decoder struct {
    // Strict默認(rèn)設(shè)為true,強(qiáng)制要求符合XML規(guī)范
    // 如果設(shè)為false,則解析器允許輸入中包含常見的錯(cuò)誤:
    //   * 如果元素缺少結(jié)束標(biāo)簽,解析器會(huì)虛構(gòu)一個(gè)結(jié)束標(biāo)簽以保證返回值來自良好平衡的Token
    //   * 屬性值和字符數(shù)據(jù)中,未知或畸形的字符entity(以&開始的序列)會(huì)丟在一邊
    //
    // 設(shè)置:
    //
    //   d.Strict = false
    //   d.AutoClose = HTMLAutoClose
    //   d.Entity = HTMLEntity
    //
    // 可以創(chuàng)建一個(gè)能處理標(biāo)準(zhǔn)HTML的解析器。
    //
    // Strict模式不會(huì)強(qiáng)制要求XML名稱空間TR,特別注意它不會(huì)拒絕使用未定義前綴的名字空間標(biāo)簽
    // 這些標(biāo)簽會(huì)將未知前綴作為名字空間URL來記錄
    Strict bool
    // 當(dāng)Strict == false時(shí),AutoClose指定一個(gè)元素的集合:
    // 這些元素在開啟后就立刻結(jié)束,不管有沒有對(duì)應(yīng)關(guān)閉標(biāo)簽存在
    AutoClose []string
    // Entity字段用于將非標(biāo)準(zhǔn)的實(shí)體名映射到替換的字符串
    // parser的行為就好像標(biāo)準(zhǔn)實(shí)體映射存在于本字段,即使實(shí)際上本字段沒有:
    //
    //  "lt": "<",
    //  "gt": ">",
    //  "amp": "&",
    //  "apos": "'",
    //  "quot": `"`,
    Entity map[string]string
    // CharsetReader字段如果非nil,會(huì)定義一個(gè)函數(shù)來生成轉(zhuǎn)換字符集的io.Reader,
    // 將給定的非utf-8字符集轉(zhuǎn)換為utf-8字符集。如果CharsetReader字段為nil
    // 或者返回一個(gè)錯(cuò)誤,解析將會(huì)停止并發(fā)揮該錯(cuò)誤。CharsetReader的返回值不能都是nil
    CharsetReader func(charset string, input io.Reader) (io.Reader, error)
    // DefaultSpace設(shè)置未修飾標(biāo)簽的默認(rèn)名字空間,就好像整個(gè)XML流都包裝進(jìn)有個(gè)具有屬性
    // xmlns="DefaultSpace"的元素內(nèi)
    DefaultSpace string
    // 內(nèi)含隱藏或非導(dǎo)出字段
}

Decoder代表一個(gè)XML解析器,可以讀取輸入流的部分?jǐn)?shù)據(jù),該解析器假定輸入是utf-8編碼的。

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

創(chuàng)建一個(gè)從r讀取XML數(shù)據(jù)的解析器。如果r未實(shí)現(xiàn)io.ByteReader接口,NewDecoder會(huì)為其添加緩存。

func (*Decoder) Decode

func (d *Decoder) Decode(v interface{}) error

Decode方法功能類似xml.Unmarshal函數(shù),但會(huì)從底層讀取XML數(shù)據(jù)并查找StartElement。

func (*Decoder) DecodeElement

func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error

DecodeElement方法的功能類似xml.Unmarshal函數(shù),但它會(huì)啟出一個(gè)指向XML起始標(biāo)簽后將解析結(jié)果寫入v。當(dāng)客戶端自己讀取了一些原始XML token但仍想defer調(diào)用Unmarshal處理一些元素時(shí)很有用。

func (*Decoder) Token

func (d *Decoder) Token() (t Token, err error)

Token返回輸入流里的下一個(gè)XML token。在輸入流的結(jié)尾處,會(huì)返回(nil, io.EOF)

返回的token數(shù)據(jù)里的[]byte數(shù)據(jù)引用自解析器內(nèi)部的緩存,只在下一次調(diào)用Token之前有效。如要獲取切片的拷貝,調(diào)用CopyToken函數(shù)或者token的Copy方法。

成功調(diào)用的Token方法會(huì)將自我閉合的元素(如
)擴(kuò)展為分離的起始和結(jié)束標(biāo)簽。

Token方法會(huì)保證它返回的StartElement和EndElement兩種token正確的嵌套和匹配:如果本方法遇到了不正確的結(jié)束標(biāo)簽,會(huì)返回一個(gè)錯(cuò)誤。

Token方法實(shí)現(xiàn)了XML名字空間,細(xì)節(jié)參見http://www.w3.org/TR/REC-xml-names/。每一個(gè)包含在Token里的Name結(jié)構(gòu)體,都會(huì)將Space字段設(shè)為URL標(biāo)識(shí)(如果可知的話)。如果Token遇到未知的名字空間前綴,它會(huì)使用該前綴作為名字空間,而不是報(bào)錯(cuò)。

func (*Decoder) RawToken

func (d *Decoder) RawToken() (Token, error)

RawToken方法Token方法,但不會(huì)驗(yàn)證起始和結(jié)束標(biāo)簽,也不將名字空間前綴翻譯為它們相應(yīng)的URL。

func (*Decoder) Skip

func (d *Decoder) Skip() error

Skip從底層讀取token,直到讀取到最近一次讀取到的起始標(biāo)簽對(duì)應(yīng)的結(jié)束標(biāo)簽。如果讀取中遇到別的起始標(biāo)簽會(huì)進(jìn)行迭代,因此可以跳過嵌套結(jié)構(gòu)。如果本方法找到了對(duì)應(yīng)起始標(biāo)簽的結(jié)束標(biāo)簽,會(huì)返回nil;否則返回一個(gè)描述該問題的錯(cuò)誤。

type Encoder

type Encoder struct {
    p printer
}

Encoder向輸出流中寫入XML數(shù)據(jù)。

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder創(chuàng)建一個(gè)寫入w的*Encoder。

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"`
}
func main() {
    v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}
    v.Comment = " Need more details. "
    v.Address = Address{"Hanga Roa", "Easter Island"}
    enc := xml.NewEncoder(os.Stdout)
    enc.Indent("  ", "    ")
    if err := enc.Encode(v); err != nil {
        fmt.Printf("error: %v\n", err)
    }
}

func (*Encoder) Encode

func (enc *Encoder) Encode(v interface{}) error

Encode將v編碼為XML后寫入底層。參見Marshal函數(shù)獲取go到XML轉(zhuǎn)換的細(xì)節(jié)。在返回前enc會(huì)調(diào)用Flush。

func (*Encoder) EncodeElement

func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error

EncodeElement將v的XML編碼寫入底層, 并使用start作為編碼的最外層。參見Marshal函數(shù)獲取go到XML轉(zhuǎn)換的細(xì)節(jié)。在返回前enc會(huì)調(diào)用Flush方法。

func (*Encoder) EncodeToken

func (enc *Encoder) EncodeToken(t Token) error

EncodeToken向底層寫入一個(gè)token。如果StartElement和EndElement的匹配不正確,本方法會(huì)返回錯(cuò)誤。

EncodeToken 方法不會(huì)調(diào)用Flush,因?yàn)樗ǔJ歉笮筒僮魅鏓ncode或EncodeElement方法的一部分(或者用戶自定義的Marshaler接口MarshalXML 方法里調(diào)用本方法),這些方法會(huì)在結(jié)束前Flush。調(diào)用者創(chuàng)建一個(gè)Encoder并直接使用本方法而不使用Encode或EncodeElement方法的話,必須在結(jié)束時(shí)調(diào)用Flush以保證XML數(shù)據(jù)寫入底層的io.Writer接口。

EncodeToken寫入ProcInst類型Token時(shí),只允許在底層流最開始寫入目標(biāo)是"xml"的ProcInst。

func (*Encoder) Flush

func (enc *Encoder) Flush() error

Flush方法會(huì)將緩存中的XML數(shù)據(jù)寫入底層。參見EncodeToken函數(shù)獲取細(xì)節(jié)信息。

func (*Encoder) Indent

func (enc *Encoder) Indent(prefix, indent string)

Indent函數(shù)設(shè)定編碼器生成XML數(shù)據(jù)時(shí)的格式化縮進(jìn)信息。細(xì)節(jié)請(qǐng)參見MarshalIndent函數(shù)。

Bugs

? XML元素和數(shù)據(jù)結(jié)構(gòu)體的映射有天生的缺陷:XML元素是依賴順序的匿名值的集合,而結(jié)構(gòu)體是不依賴順序的命名值的集合。參見json包獲取更適用于數(shù)據(jù)結(jié)構(gòu)體的文本表示。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容