美文网首页
Golang标准库——encoding(3)

Golang标准库——encoding(3)

作者: DevilRoshan | 来源:发表于2020-09-28 23:57 被阅读0次
    • json
    • pem
    • xml

    json

    json包实现了json对象的编解码,参见RFC 4627。Json对象和go类型的映射关系请参见Marshal和Unmarshal函数的文档。

    参见"JSON and Go"获取本包的一个介绍:http://golang.org/doc/articles/json_and_go.html

    type InvalidUTF8Error

    type InvalidUTF8Error struct {
        S string // 引发错误的完整字符串
    }
    

    Go 1.2之前版本,当试图编码一个包含非法utf-8序列的字符串时会返回本错误。Go 1.2及之后版本,编码器会强行将非法字节替换为unicode字符U+FFFD来使字符串合法。本错误已不会再出现,但出于向后兼容考虑而保留。

    func (*InvalidUTF8Error) Error

    func (e *InvalidUTF8Error) Error() string
    

    type InvalidUnmarshalError

    type InvalidUnmarshalError struct {
        Type reflect.Type
    }
    

    InvalidUnmarshalError用于描述一个传递给解码器的非法参数。(解码器的参数必须是非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表示一个json语法错误。

    func (*SyntaxError) Error

    func (e *SyntaxError) Error() string
    

    type UnmarshalFieldError

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

    UnmarshalFieldError表示一个json对象的键指向一个非导出字段。(因此不能写入;已不再使用,出于兼容保留)

    func (*UnmarshalFieldError) Error

    func (e *UnmarshalFieldError) Error() string
    

    type UnmarshalTypeError

    type UnmarshalTypeError struct {
        Value string       // 描述json值:"bool", "array", "number -5"
        Type  reflect.Type // 不能转化为的go类型
    }
    

    UnmarshalTypeError表示一个json值不能转化为特定的go类型的值。

    func (*UnmarshalTypeError) Error

    func (e *UnmarshalTypeError) Error() string
    

    type UnsupportedTypeError

    type UnsupportedTypeError struct {
        Type reflect.Type
    }
    

    UnsupportedTypeError表示试图编码一个不支持类型的值。

    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类型代表一个json数字字面量。

    func (Number) Int64

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

    将该数字作为int64类型返回。

    func (Number) Float64

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

    将该数字作为float64类型返回。

    func (Number) String

    func (n Number) String() string
    

    返回该数字的字面值文本表示。

    type RawMessage

    type RawMessage []byte
    

    RawMessage类型是一个保持原本编码的json对象。本类型实现了Marshaler和Unmarshaler接口,用于延迟json的解码或者预计算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设为data的一个拷贝。

    type Marshaler

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

    实现了Marshaler接口的类型可以将自身序列化为合法的json描述。

    type Unmarshaler

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

    实现了Unmarshaler接口的对象可以将自身的json描述反序列化。该方法可以认为输入是合法的json字符串。如果要在方法返回后保存自身的json数据,必须进行拷贝。

    func Compact

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

    Compact函数将json编码的src中无用的空白字符剔除后写入dst。

    func HTMLEscape

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

    HTMLEscape 函数将json编码的src中的<、>、&、U+2028 和U+2029字符替换为\u003c、\u003e、\u0026、\u2028、\u2029 转义字符串,以便json编码可以安全的嵌入HTML的<script>标签里。因为历史原因,网络浏览器不支持在<script>标签中使用标准HTML转义, 因此必须使用另一种json编码方案。

    func Indent

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

    Indent函数将json编码的调整缩进之后写入dst。每一个json元素/数组都另起一行开始,以prefix为起始,一或多个indent缩进(数目看嵌套层数)。写入dst的数据起始没有prefix字符,也没有indent字符,最后也不换行,因此可以更好的嵌入其他格式化后的json数据里。

    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函数返回v的json编码。

    Marshal函数会递归的处理值。如果一个值实现了Marshaler接口切非nil指针,会调用其MarshalJSON方法来生成json编码。nil指针异常并不是严格必需的,但会模拟与UnmarshalJSON的行为类似的必需的异常。

    否则,Marshal函数使用下面的基于类型的默认编码格式:

    布尔类型编码为json布尔类型。

    浮点数、整数和Number类型的值编码为json数字类型。

    字符串编码为json字符串。角括号"<"和">"会转义为"\u003c"和"\u003e"以避免某些浏览器吧json输出错误理解为HTML。基于同样的原因,"&"转义为"\u0026"。

    数组和切片类型的值编码为json数组,但[]byte编码为base64编码字符串,nil切片编码为null。

    结构体的值编码为json对象。每一个导出字段变成该对象的一个成员,除非:

    - 字段的标签是"-"
    - 字段是空值,而其标签指定了omitempty选项
    

    空值是false、0、""、nil指针、nil接口、长度为0的数组、切片、映射。对象默认键字符串是结构体的字段名,但可以在结构体字段的标签里指定。结构体标签值里的"json"键为键名,后跟可选的逗号和选项,举例如下:

    // 字段被本包忽略
    Field int `json:"-"`
    // 字段在json里的键为"myName"
    Field int `json:"myName"`
    // 字段在json里的键为"myName"且如果字段为空值将在对象中省略掉
    Field int `json:"myName,omitempty"`
    // 字段在json里的键为"Field"(默认值),但如果字段为空值会跳过;注意前导的逗号
    Field int `json:",omitempty"`
    

    "string"选项标记一个字段在编码json时应编码为字符串。它只适用于字符串、浮点数、整数类型的字段。这个额外水平的编码选项有时候会用于和javascript程序交互:

    Int64String int64 `json:",string"`
    

    如果键名是只含有unicode字符、数字、美元符号、百分号、连字符、下划线和斜杠的非空字符串,将使用它代替字段名。

    匿名的结构体字段一般序列化为他们内部的导出字段就好像位于外层结构体中一样。如果一个匿名结构体字段的标签给其提供了键名,则会使用键名代替字段名,而不视为匿名。

    Go结构体字段的可视性规则用于供json决定那个字段应该序列化或反序列化时是经过修正了的。如果同一层次有多个(匿名)字段且该层次是最小嵌套的(嵌套层次则使用默认go规则),会应用如下额外规则:

    1)json标签为"-"的匿名字段强行忽略,不作考虑;

    2)json标签提供了键名的匿名字段,视为非匿名字段;

    3)其余字段中如果只有一个匿名字段,则使用该字段;

    4)其余字段中如果有多个匿名字段,但压平后不会出现冲突,所有匿名字段压平;

    5)其余字段中如果有多个匿名字段,但压平后出现冲突,全部忽略,不产生错误。

    对匿名结构体字段的管理是从go1.1开始的,在之前的版本,匿名字段会直接忽略掉。

    映射类型的值编码为json对象。映射的键必须是字符串,对象的键直接使用映射的键。

    指针类型的值编码为其指向的值(的json编码)。nil指针编码为null。

    接口类型的值编码为接口内保持的具体类型的值(的json编码)。nil接口编码为null。

    通道、复数、函数类型的值不能编码进json。尝试编码它们会导致Marshal函数返回UnsupportedTypeError。

    Json不能表示循环的数据结构,将一个循环的结构提供给Marshal函数会导致无休止的循环。

    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但会使用缩进将输出格式化。

    func Unmarshal

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

    Unmarshal函数解析json编码的数据并将结果存入v指向的值。

    Unmarshal和Marshal做相反的操作,必要时申请映射、切片或指针,有如下的附加规则:

    要将json数据解码写入一个指针,Unmarshal函数首先处理json数据是json字面值null的情况。此时,函数将指针设为nil;否则,函数将json数据解码写入指针指向的值;如果指针本身是nil,函数会先申请一个值并使指针指向它。

    要将json数据解码写入一个结构体,函数会匹配输入对象的键和Marshal使用的键(结构体字段名或者它的标签指定的键名),优先选择精确的匹配,但也接受大小写不敏感的匹配。

    要将json数据解码写入一个接口类型值,函数会将数据解码为如下类型写入接口:

    Bool                   对应JSON布尔类型
    float64                对应JSON数字类型
    string                 对应JSON字符串类型
    []interface{}          对应JSON数组
    map[string]interface{} 对应JSON对象
    nil                    对应JSON的null
    

    如果一个JSON值不匹配给出的目标类型,或者如果一个json数字写入目标类型时溢出,Unmarshal函数会跳过该字段并尽量完成其余的解码操作。如果没有出现更加严重的错误,本函数会返回一个描述第一个此类错误的详细信息的UnmarshalTypeError。

    JSON的null值解码为go的接口、指针、切片时会将它们设为nil,因为null在json里一般表示“不存在”。 解码json的null值到其他go类型时,不会造成任何改变,也不会产生错误。
    当解码字符串时,不合法的utf-8或utf-16代理(字符)对不视为错误,而是将非法字符替换为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对象

    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创建一个从r读取并解码json对象的*Decoder,解码器有自己的缓冲,并可能超前读取部分json数据。

    func (*Decoder) Buffered

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

    Buffered方法返回保存在dec缓存里数据的读取器,该返回值在下次调用Decode方法之前有效。

    func (*Decoder) UseNumber

    func (dec *Decoder) UseNumber()
    

    UseNumber方法将dec设置为当接收端是interface{}接口时将json数字解码为Number类型而不是float64类型

    func (*Decoder) Decode

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

    Decode从输入流读取下一个json编码值并保存在v指向的值里,参见Unmarshal函数的文档获取细节信息。

    type Encoder

    type Encoder struct {
        w          io.Writer
        err        error
        escapeHTML bool
    
        indentBuf    *bytes.Buffer
        indentPrefix string
        indentValue  string
    }
    

    Encoder将json对象写入输出流。

    func NewEncoder

    func NewEncoder(w io.Writer) *Encoder
    

    NewEncoder创建一个将数据写入w的*Encoder。

    func (*Encoder) Encode

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

    Encode将v的json编码写入输出流,并会写入一个换行符,参见Marshal函数的文档获取细节信息。

    pem

    pem包实现了PEM数据编码(源自保密增强邮件协议)。目前PEM编码主要用于TLS密钥和证书。参见RFC 1421

    type Block

    type Block struct {
        Type    string            // 得自前言的类型(如"RSA PRIVATE KEY")
        Headers map[string]string // 可选的头项
        Bytes   []byte            // 内容解码后的数据,一般是DER编码的ASN.1结构
    }
    

    Block代表PEM编码的结构。编码格式如下:

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

    其中Headers是可为空的多行键值对。

    func Decode

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

    Decode函数会从输入里查找到下一个PEM格式的块(证书、私钥等)。它返回解码得到的Block和剩余未解码的数据。如果未发现PEM数据,返回(nil, data)。

    func Encode

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

    func EncodeToMemory

    func EncodeToMemory(b *Block) []byte
    

    xml

    xml包实现了一个简单的XML 1.0解析器,该解析器可以理解XML名称空间。

    Constants

    const (
        // 适用于本包Marshal输出的一般性XML header
        // 本常数并不会自动添加到本包的输出里,这里提供主要是出于便利的目的
        Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
    )
    

    Variables

    var HTMLAutoClose = htmlAutoClose
    

    HTMLAutoClose是应当考虑到自动关闭的HTML元素的集合。

    var HTMLEntity = htmlEntity
    

    HTMLEntity是标准HTML entity字符到其翻译的映射。

    type SyntaxError

    type SyntaxError struct {
        Msg  string
        Line int
    }
    

    SyntaxError代表XML输入流的格式错误。

    func (*SyntaxError) Error

    func (e *SyntaxError) Error() string
    

    type TagPathError

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

    反序列化时,如果字段标签的路径有冲突,就会返回TagPathError。

    func (*TagPathError) Error

    func (e *TagPathError) Error() string
    

    type UnsupportedTypeError

    type UnsupportedTypeError struct {
        Type reflect.Type
    }
    

    当序列化时,如果遇到不能转化为XML的类型,就会返回UnsupportedTypeError。

    func (*UnsupportedTypeError) Error

    func (e *UnsupportedTypeError) Error() string
    

    type UnmarshalError

    type UnmarshalError string
    

    UnmarshalError代表反序列化时出现的错误。

    func (UnmarshalError) Error

    func (e UnmarshalError) Error() string
    

    type CharData

    type CharData []byte
    

    CharData类型代表XML字符数据(原始文本),其中XML转义序列已经被它们所代表的字符取代。

    func (CharData) Copy

    func (c CharData) Copy() CharData
    

    type Comment

    type Comment []byte
    

    Comment代表XML注释,格式为,切片中不包含注释标记<!—和-->。

    func (Comment) Copy

    func (c Comment) Copy() Comment
    

    type Directive

    type Directive []byte
    

    Directive代表XML指示,格式为<!directive>,切片中不包含标记<!和>。

    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代表一个XML名称(Local字段),并指定名字空间(Space)。Decoder.Token方法返回的Token中,Space标识符是典型的URL而不是被解析的文档里的短前缀。

    type Attr

    type Attr struct {
        Name  Name
        Value string
    }
    

    Attr代表一个XML元素的一条属性(Name=Value)

    type StartElement

    type StartElement struct {
        Name Name
        Attr []Attr
    }
    

    StartElement代表一个XML起始元素。

    func (StartElement) Copy

    func (e StartElement) Copy() StartElement
    

    func (StartElement) End

    func (e StartElement) End() EndElement
    

    返回e对应的XML结束元素。

    type EndElement

    type EndElement struct {
        Name Name
    }
    

    EndElement代表一个XML结束元素。

    type Token

    type Token interface{}
    

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

    func CopyToken

    func CopyToken(t Token) Token
    

    CopyToken返回一个Token的拷贝。

    type Marshaler

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

    实现了Marshaler接口的类型可以将自身序列化为合法的XML元素。

    MarshalXML方法将自身调用者编码为零或多个XML元素。 按照惯例,数组或切片会编码为一系列元素,每个成员一条。使用start作为元素标签并不是必须的,但这么做可以帮助Unmarshal方法正确的匹配XML元素和结构体字段。一个常用的策略是在同一个层次里将每个独立的值对应到期望的XML然后使用e.EncodeElement进行编码。另一个常用的策略是重复调用e.EncodeToken来一次一个token的生成XML输出。编码后的token必须组成零或多个XML元素。

    type Unmarshaler

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

    实现了Unmarshaler接口的类型可以根据自身的XML元素描述反序列化自身。

    UnmarshalXML方法解码以start起始单个XML元素。如果它返回了错误,外层Unmarshal的调用将停止执行并返回该错误。UnmarshalXML方法必须正好“消费”一个XML元素。一个常用的策略是使用d.DecodeElement 将XML分别解码到各独立值,然后再将这些值写入UnmarshalXML的调用者。另一个常用的策略是使用d.Token一次一个token的处理XML对象。UnmarshalXML通常不使用d.RawToken。

    type MarshalerAttr

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

    实现了MarshalerAttr接口的类型可以将自身序列化为合法的XML属性。

    MarshalXMLAttr返回一个值为方法调用者编码后的值的XML属性。使用name作为属性的name并非必须的,但这么做可以帮助Unmarshal方法正确的匹配属性和结构体字段。如果MarshalXMLAttr返回一个零值属性Attr{},将不会生成属性输出。MarshalXMLAttr只用于有标签且标签有"attr"选项的结构体字段。

    type UnmarshalerAttr

    type UnmarshalerAttr interface {
        UnmarshalXMLAttr(attr Attr) error
    }
    

    实现了UnmarshalerAttr接口的类型可以根据自身的XML属性形式的描述反序列化自身。

    UnmarshalXMLAttr解码单个的XML属性。如果它返回一个错误,外层的Umarshal调用会停止执行并返回该错误。UnmarshalXMLAttr只有在结构体字段的标签有"attr"选项时才被使用。

    func Escape

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

    Escape类似EscapeText函数但会忽略返回的错误。本函数是用于保证和Go 1.0的向后兼容。应用于Go 1.1及以后版本的代码请使用EscapeText。

    func EscapeText

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

    EscapeText向w中写入经过适当转义的、有明文s具有相同意义的XML文本。

    func Marshal

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

    Marshal函数返回v的XML编码。

    Marshal处理数组或者切片时会序列化每一个元素。Marshal处理指针时,会序列化其指向的值;如果指针为nil,则啥也不输出。Marshal处理接口时,会序列化其内包含的具体类型值,如果接口值为nil,也是不输出。Marshal处理其余类型数据时,会输出一或多个包含数据的XML元素。

    XML元素的名字按如下优先顺序获取:

    - 如果数据是结构体,其XMLName字段的标签
    - 类型为xml.Name的XMLName字段的值
    - 数据是某结构体的字段,其标签
    - 数据是某结构体的字段,其字段名
    - 被序列化的类型的名字
    

    一个结构体的XML元素包含该结构体所有导出字段序列化后的元素,有如下例外:

    - XMLName字段,如上所述,会省略
    - 具有标签"-"的字段会省略
    - 具有标签"name,attr"的字段会成为该XML元素的名为name的属性
    - 具有标签",attr"的字段会成为该XML元素的名为字段名的属性
    - 具有标签",chardata"的字段会作为字符数据写入,而非XML元素
    - 具有标签",innerxml"的字段会原样写入,而不会经过正常的序列化过程
    - 具有标签",comment"的字段作为XML注释写入,而不经过正常的序列化过程,该字段内不能有"--"字符串
    - 标签中包含"omitempty"选项的字段如果为空值会省略
      空值为false、0、nil指针、nil接口、长度为0的数组、切片、映射
    - 匿名字段(其标签无效)会被处理为其字段是外层结构体的字段
    

    如果一个字段的标签为"a>b>c",则元素c将会嵌套进其上层元素a和b中。如果该字段相邻的字段标签指定了同样的上层元素,则会放在同一个XML元素里。

    参见MarshalIndent的例子。如果要求Marshal序列化通道、函数或者映射会返回错误。

    func MarshalIndent

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

    MarshalIndent功能类似Marshal。但每个XML元素会另起一行并缩进,该行以prefix起始,后跟一或多个indent的拷贝(根据嵌套层数)。

    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编码的数据并将结果存入v指向的值。v只能指向结构体、切片或者和字符串。良好格式化的数据如果不能存入v,会被丢弃。

    因为Unmarshal使用reflect包,它只能填写导出字段。本函数好似用大小写敏感的比较来匹配XML元素名和结构体的字段名/标签键名。

    Unmarshal函数使用如下规则将XML元素映射到结构体字段上。这些规则中,字段标签指的是结构体字段的标签键'xml'对应的值(参见上面的例子):

    * 如果结构体字段的类型为字符串或者[]byte,且标签为",innerxml",
      Unmarshal函数直接将对应原始XML文本写入该字段,其余规则仍适用。
    * 如果结构体字段类型为xml.Name且名为XMLName,Unmarshal会将元素名写入该字段
    * 如果字段XMLName的标签的格式为"name"或"namespace-URL name",
      XML元素必须有给定的名字(以及可选的名字空间),否则Unmarshal会返回错误。
    * 如果XML元素的属性的名字匹配某个标签",attr"为字段的字段名,或者匹配某个标签为"name,attr"
      的字段的标签名,Unmarshal会将该属性的值写入该字段。
    * 如果XML元素包含字符数据,该数据会存入结构体中第一个具有标签",chardata"的字段中,
      该字段可以是字符串类型或者[]byte类型。如果没有这样的字段,字符数据会丢弃。
    * 如果XML元素包含注释,该数据会存入结构体中第一个具有标签",comment"的字段中,
      该字段可以是字符串类型或者[]byte类型。如果没有这样的字段,字符数据会丢弃。
    * 如果XML元素包含一个子元素,其名称匹配格式为"a"或"a>b>c"的标签的前缀,反序列化会深入
      XML结构中寻找具有指定名称的元素,并将最后端的元素映射到该标签所在的结构体字段。
      以">"开始的标签等价于以字段名开始并紧跟着">" 的标签。
    * 如果XML元素包含一个子元素,其名称匹配某个结构体类型字段的XMLName字段的标签名,
      且该结构体字段本身没有显式指定标签名,Unmarshal会将该元素映射到该字段。
    * 如果XML元素的包含一个子元素,其名称匹配够格结构体字段的字段名,且该字段没有任何模式选项
      (",attr"、",chardata"等),Unmarshal会将该元素映射到该字段。
    * 如果XML元素包含的某个子元素不匹配以上任一条,而存在某个字段其标签为",any",
      Unmarshal会将该元素映射到该字段。
    * 匿名字段被处理为其字段好像位于外层结构体中一样。
    * 标签为"-"的结构体字段永不会被反序列化填写。
    

    Unmarshal函数将XML元素写入string或[]byte时,会将该元素的字符数据串联起来作为值,目标[]byte不能是nil。

    Unmarshal函数将属性写入string或[]byte时,会将属性的值以字符串/切片形式写入。

    Unmarshal函数将XML元素写入切片时,会将切片扩展并将XML元素的子元素映射入新建的值里。

    Unmarshal函数将XML元素/属性写入bool值时,会将对应的字符串转化为布尔值。

    Unmarshal函数将XML元素/属性写入整数或浮点数类型时,会将对应的字符串解释为十进制数字。不会检查溢出。

    Unmarshal函数将XML元素写入xml.Name类型时,会记录元素的名称。

    Unmarshal函数将XML元素写入指针时,会申请一个新值并将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默认设为true,强制要求符合XML规范
        // 如果设为false,则解析器允许输入中包含常见的错误:
        //   * 如果元素缺少结束标签,解析器会虚构一个结束标签以保证返回值来自良好平衡的Token
        //   * 属性值和字符数据中,未知或畸形的字符entity(以&开始的序列)会丢在一边
        //
        // 设置:
        //
        //   d.Strict = false
        //   d.AutoClose = HTMLAutoClose
        //   d.Entity = HTMLEntity
        //
        // 可以创建一个能处理标准HTML的解析器。
        //
        // Strict模式不会强制要求XML名称空间TR,特别注意它不会拒绝使用未定义前缀的名字空间标签
        // 这些标签会将未知前缀作为名字空间URL来记录
        Strict bool
        // 当Strict == false时,AutoClose指定一个元素的集合:
        // 这些元素在开启后就立刻结束,不管有没有对应关闭标签存在
        AutoClose []string
        // Entity字段用于将非标准的实体名映射到替换的字符串
        // parser的行为就好像标准实体映射存在于本字段,即使实际上本字段没有:
        //
        //  "lt": "<",
        //  "gt": ">",
        //  "amp": "&",
        //  "apos": "'",
        //  "quot": `"`,
        Entity map[string]string
        // CharsetReader字段如果非nil,会定义一个函数来生成转换字符集的io.Reader,
        // 将给定的非utf-8字符集转换为utf-8字符集。如果CharsetReader字段为nil
        // 或者返回一个错误,解析将会停止并发挥该错误。CharsetReader的返回值不能都是nil
        CharsetReader func(charset string, input io.Reader) (io.Reader, error)
        // DefaultSpace设置未修饰标签的默认名字空间,就好像整个XML流都包装进有个具有属性
        // xmlns="DefaultSpace"的元素内
        DefaultSpace string
        // 内含隐藏或非导出字段
    }
    

    Decoder代表一个XML解析器,可以读取输入流的部分数据,该解析器假定输入是utf-8编码的。

    func NewDecoder

    func NewDecoder(r io.Reader) *Decoder
    

    创建一个从r读取XML数据的解析器。如果r未实现io.ByteReader接口,NewDecoder会为其添加缓存。

    func (*Decoder) Decode

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

    Decode方法功能类似xml.Unmarshal函数,但会从底层读取XML数据并查找StartElement。

    func (*Decoder) DecodeElement

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

    DecodeElement方法的功能类似xml.Unmarshal函数,但它会启出一个指向XML起始标签后将解析结果写入v。当客户端自己读取了一些原始XML token但仍想defer调用Unmarshal处理一些元素时很有用。

    func (*Decoder) Token

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

    Token返回输入流里的下一个XML token。在输入流的结尾处,会返回(nil, io.EOF)

    返回的token数据里的[]byte数据引用自解析器内部的缓存,只在下一次调用Token之前有效。如要获取切片的拷贝,调用CopyToken函数或者token的Copy方法。

    成功调用的Token方法会将自我闭合的元素(如
    )扩展为分离的起始和结束标签。

    Token方法会保证它返回的StartElement和EndElement两种token正确的嵌套和匹配:如果本方法遇到了不正确的结束标签,会返回一个错误。

    Token方法实现了XML名字空间,细节参见http://www.w3.org/TR/REC-xml-names/。每一个包含在Token里的Name结构体,都会将Space字段设为URL标识(如果可知的话)。如果Token遇到未知的名字空间前缀,它会使用该前缀作为名字空间,而不是报错。

    func (*Decoder) RawToken

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

    RawToken方法Token方法,但不会验证起始和结束标签,也不将名字空间前缀翻译为它们相应的URL。

    func (*Decoder) Skip

    func (d *Decoder) Skip() error
    

    Skip从底层读取token,直到读取到最近一次读取到的起始标签对应的结束标签。如果读取中遇到别的起始标签会进行迭代,因此可以跳过嵌套结构。如果本方法找到了对应起始标签的结束标签,会返回nil;否则返回一个描述该问题的错误。

    type Encoder

    type Encoder struct {
        p printer
    }
    

    Encoder向输出流中写入XML数据。

    func NewEncoder

    func NewEncoder(w io.Writer) *Encoder
    

    NewEncoder创建一个写入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函数获取go到XML转换的细节。在返回前enc会调用Flush。

    func (*Encoder) EncodeElement

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

    EncodeElement将v的XML编码写入底层, 并使用start作为编码的最外层。参见Marshal函数获取go到XML转换的细节。在返回前enc会调用Flush方法。

    func (*Encoder) EncodeToken

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

    EncodeToken向底层写入一个token。如果StartElement和EndElement的匹配不正确,本方法会返回错误。

    EncodeToken 方法不会调用Flush,因为它通常是更大型操作如Encode或EncodeElement方法的一部分(或者用户自定义的Marshaler接口MarshalXML 方法里调用本方法),这些方法会在结束前Flush。调用者创建一个Encoder并直接使用本方法而不使用Encode或EncodeElement方法的话,必须在结束时调用Flush以保证XML数据写入底层的io.Writer接口。

    EncodeToken写入ProcInst类型Token时,只允许在底层流最开始写入目标是"xml"的ProcInst。

    func (*Encoder) Flush

    func (enc *Encoder) Flush() error
    

    Flush方法会将缓存中的XML数据写入底层。参见EncodeToken函数获取细节信息。

    func (*Encoder) Indent

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

    Indent函数设定编码器生成XML数据时的格式化缩进信息。细节请参见MarshalIndent函数。

    Bugs

    XML元素和数据结构体的映射有天生的缺陷:XML元素是依赖顺序的匿名值的集合,而结构体是不依赖顺序的命名值的集合。参见json包获取更适用于数据结构体的文本表示。

    相关文章

      网友评论

          本文标题:Golang标准库——encoding(3)

          本文链接:https://www.haomeiwen.com/subject/qarsuktx.html