JSON 与 XML 处理

35.1 JSON 基础

JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,Go 通过 encoding/json 包提供支持。

JSON 数据类型对应

JSON 类型Go 类型
对象map[string]interface{} / struct
数组[]interface{} / slice
字符串string
数字float64 / int
布尔bool
nullnil

35.2 JSON 序列化

结构体转 JSON

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name    string `json:"name"`
    Age     int    `json:"age"`
    Email   string `json:"email"`
    Address string `json:"address,omitempty"`
}

func main() {
    person := Person{
        Name:  "Alice",
        Age:   30,
        Email: "alice@example.com",
    }

    // 序列化为 JSON 字节
    data, err := json.Marshal(person)
    if err != nil {
        fmt.Println("序列化失败:", err)
        return
    }

    fmt.Println(string(data))
    // {"name":"Alice","age":30,"email":"alice@example.com"}
}

格式化输出

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    person := Person{
        Name: "Alice",
        Age:  30,
    }

    // 格式化输出(带缩进)
    data, _ := json.MarshalIndent(person, "", "  ")
    fmt.Println(string(data))
    // {
    //   "name": "Alice",
    //   "age": 30
    // }
}

结构体标签

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int    `json:"id"`                   // 字段名
    Name     string `json:"name"`                 // 字段名
    Password string `json:"-"`                    // 忽略此字段
    Email    string `json:"email,omitempty"`      // 为空时忽略
    Phone    string `json:"phone,string"`         // 转为字符串
    Status   bool   `json:",omitempty"`           // 使用字段名,为空时忽略
}

func main() {
    user := User{
        ID:     1,
        Name:   "Alice",
        Email:  "alice@example.com",
        Status: true,
    }

    data, _ := json.MarshalIndent(user, "", "  ")
    fmt.Println(string(data))
}

Map 转 JSON

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    data := map[string]interface{}{
        "name":  "Alice",
        "age":   30,
        "email": "alice@example.com",
        "tags":  []string{"go", "web"},
    }

    jsonData, _ := json.MarshalIndent(data, "", "  ")
    fmt.Println(string(jsonData))
}

Slice 转 JSON

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    persons := []Person{
        {Name: "Alice", Age: 30},
        {Name: "Bob", Age: 25},
        {Name: "Charlie", Age: 35},
    }

    jsonData, _ := json.MarshalIndent(persons, "", "  ")
    fmt.Println(string(jsonData))
}

35.3 JSON 反序列化

JSON 转结构体

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    jsonData := `{"name": "Alice", "age": 30}`

    var person Person
    err := json.Unmarshal([]byte(jsonData), &person)
    if err != nil {
        fmt.Println("反序列化失败:", err)
        return
    }

    fmt.Printf("%+v\n", person) // {Name:Alice Age:30}
}

JSON 转 Map

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonData := `{"name": "Alice", "age": 30, "active": true}`

    var data map[string]interface{}
    json.Unmarshal([]byte(jsonData), &data)

    fmt.Printf("%+v\n", data)
    fmt.Printf("name: %v\n", data["name"])
    fmt.Printf("age: %v\n", data["age"])
}

JSON 转 Slice

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonData := `[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]`

    var persons []map[string]interface{}
    json.Unmarshal([]byte(jsonData), &persons)

    for _, p := range persons {
        fmt.Printf("%+v\n", p)
    }
}

处理未知结构

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonData := `{
        "name": "Alice",
        "age": 30,
        "address": {
            "city": "Beijing",
            "country": "China"
        },
        "tags": ["go", "web"]
    }`

    var data map[string]interface{}
    json.Unmarshal([]byte(jsonData), &data)

    // 类型断言访问嵌套数据
    if address, ok := data["address"].(map[string]interface{}); ok {
        fmt.Println("城市:", address["city"])
    }

    if tags, ok := data["tags"].([]interface{}); ok {
        for _, tag := range tags {
            fmt.Println("标签:", tag)
        }
    }
}

35.4 流式 JSON 处理

json.Encoder

package main

import (
    "encoding/json"
    "os"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    persons := []Person{
        {Name: "Alice", Age: 30},
        {Name: "Bob", Age: 25},
    }

    file, _ := os.Create("persons.json")
    defer file.Close()

    encoder := json.NewEncoder(file)
    encoder.SetIndent("", "  ")
    encoder.Encode(persons)
}

json.Decoder

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    file, _ := os.Open("persons.json")
    defer file.Close()

    var persons []Person
    decoder := json.NewDecoder(file)
    decoder.Decode(&persons)

    for _, p := range persons {
        fmt.Printf("%+v\n", p)
    }
}

流式读取大文件

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

func main() {
    jsonData := `{"name": "Alice", "age": 30}
{"name": "Bob", "age": 25}
{"name": "Charlie", "age": 35}`

    decoder := json.NewDecoder(strings.NewReader(jsonData))

    for decoder.More() {
        var person map[string]interface{}
        if err := decoder.Decode(&person); err != nil {
            break
        }
        fmt.Printf("%+v\n", person)
    }
}

35.5 自定义 JSON 编码

实现 MarshalJSON

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

type Person struct {
    Name string
    Age  int
}

func (p Person) MarshalJSON() ([]byte, error) {
    type Alias Person
    return json.Marshal(&struct {
        *Alias
        NameUpper string `json:"name_upper"`
    }{
        Alias:     (*Alias)(&p),
        NameUpper: strings.ToUpper(p.Name),
    })
}

func main() {
    person := Person{Name: "Alice", Age: 30}
    data, _ := json.MarshalIndent(person, "", "  ")
    fmt.Println(string(data))
}

实现 UnmarshalJSON

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

type Person struct {
    Name string
    Age  int
}

func (p *Person) UnmarshalJSON(data []byte) error {
    type Alias Person
    aux := &struct {
        *Alias
        NameUpper string `json:"name_upper"`
    }{
        Alias: (*Alias)(p),
    }

    if err := json.Unmarshal(data, &aux); err != nil {
        return err
    }

    if aux.NameUpper != "" {
        p.Name = strings.Title(strings.ToLower(aux.NameUpper))
    }

    return nil
}

func main() {
    jsonData := `{"Name": "", "Age": 30, "name_upper": "ALICE"}`

    var person Person
    json.Unmarshal([]byte(jsonData), &person)

    fmt.Printf("%+v\n", person)
}

35.6 XML 处理

XML 序列化

package main

import (
    "encoding/xml"
    "fmt"
)

type Person struct {
    XMLName xml.Name `xml:"person"`
    Name    string   `xml:"name"`
    Age     int      `xml:"age"`
    Email   string   `xml:"email,omitempty"`
}

func main() {
    person := Person{
        Name:  "Alice",
        Age:   30,
        Email: "alice@example.com",
    }

    data, _ := xml.MarshalIndent(person, "", "  ")
    fmt.Println(string(data))
    // <person>
    //   <name>Alice</name>
    //   <age>30</age>
    //   <email>alice@example.com</email>
    // </person>
}

XML 标签

package main

import (
    "encoding/xml"
    "fmt"
)

type Person struct {
    XMLName  xml.Name `xml:"person"`
    ID       int      `xml:"id,attr"`           // 属性
    Name     string   `xml:"name"`              // 元素
    Age      int      `xml:"age"`               // 元素
    Password string   `xml:"-"`                 // 忽略
    Address  string   `xml:"address,omitempty"` // 为空时忽略
    InnerXML string   `xml:",innerxml"`         // 内部 XML
    Comment  string   `xml:",comment"`          // 注释
}

func main() {
    person := Person{
        ID:   1,
        Name: "Alice",
        Age:  30,
    }

    data, _ := xml.MarshalIndent(person, "", "  ")
    fmt.Println(string(data))
}

XML 反序列化

package main

import (
    "encoding/xml"
    "fmt"
)

type Person struct {
    XMLName xml.Name `xml:"person"`
    Name    string   `xml:"name"`
    Age     int      `xml:"age"`
}

func main() {
    xmlData := `
    <person>
        <name>Alice</name>
        <age>30</age>
    </person>
    `

    var person Person
    err := xml.Unmarshal([]byte(xmlData), &person)
    if err != nil {
        fmt.Println("反序列化失败:", err)
        return
    }

    fmt.Printf("%+v\n", person)
}

嵌套 XML

package main

import (
    "encoding/xml"
    "fmt"
)

type Address struct {
    City    string `xml:"city"`
    Country string `xml:"country"`
}

type Person struct {
    XMLName xml.Name `xml:"person"`
    Name    string   `xml:"name"`
    Address Address  `xml:"address"`
}

func main() {
    xmlData := `
    <person>
        <name>Alice</name>
        <address>
            <city>Beijing</city>
            <country>China</country>
        </address>
    </person>
    `

    var person Person
    xml.Unmarshal([]byte(xmlData), &person)

    fmt.Printf("%+v\n", person)
    fmt.Printf("城市: %s\n", person.Address.City)
}

XML 属性

package main

import (
    "encoding/xml"
    "fmt"
)

type Book struct {
    XMLName xml.Name `xml:"book"`
    ID      string   `xml:"id,attr"`
    Title   string   `xml:"title,attr"`
    Author  string   `xml:"author"`
    Price   float64  `xml:"price"`
}

func main() {
    xmlData := `
    <book id="001" title="Go Programming">
        <author>John Doe</author>
        <price>29.99</price>
    </book>
    `

    var book Book
    xml.Unmarshal([]byte(xmlData), &book)

    fmt.Printf("ID: %s\n", book.ID)
    fmt.Printf("Title: %s\n", book.Title)
    fmt.Printf("Author: %s\n", book.Author)
    fmt.Printf("Price: %.2f\n", book.Price)
}

35.7 实战案例

配置文件处理

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Config struct {
    Server struct {
        Host string `json:"host"`
        Port int    `json:"port"`
    } `json:"server"`
    Database struct {
        Host     string `json:"host"`
        Port     int    `json:"port"`
        Name     string `json:"name"`
        User     string `json:"user"`
        Password string `json:"password"`
    } `json:"database"`
    LogLevel string `json:"log_level"`
}

func LoadConfig(filename string) (*Config, error) {
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    var config Config
    decoder := json.NewDecoder(file)
    if err := decoder.Decode(&config); err != nil {
        return nil, err
    }

    return &config, nil
}

func main() {
    config := &Config{}
    config.Server.Host = "localhost"
    config.Server.Port = 8080
    config.Database.Host = "localhost"
    config.Database.Port = 3306
    config.Database.Name = "mydb"
    config.Database.User = "root"
    config.Database.Password = "password"
    config.LogLevel = "info"

    data, _ := json.MarshalIndent(config, "", "  ")
    fmt.Println(string(data))
}

API 响应处理

package main

import (
    "encoding/json"
    "fmt"
)

type Response struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func SuccessResponse(data interface{}) []byte {
    resp := Response{
        Code:    0,
        Message: "success",
        Data:    data,
    }
    jsonData, _ := json.Marshal(resp)
    return jsonData
}

func ErrorResponse(code int, message string) []byte {
    resp := Response{
        Code:    code,
        Message: message,
    }
    jsonData, _ := json.Marshal(resp)
    return jsonData
}

func main() {
    user := User{ID: 1, Name: "Alice", Email: "alice@example.com"}

    fmt.Println(string(SuccessResponse(user)))
    fmt.Println(string(ErrorResponse(404, "User not found")))
}

35.8 小结

本章详细介绍了 Go 语言的 JSON 和 XML 处理:

  1. JSON 序列化:使用 json.Marshaljson.MarshalIndent
  2. JSON 反序列化:使用 json.Unmarshal
  3. 结构体标签json:"name"json:"-"json:",omitempty"
  4. 流式处理:使用 json.Encoderjson.Decoder
  5. 自定义编码:实现 MarshalJSONUnmarshalJSON
  6. XML 处理:使用 xml.Marshalxml.Unmarshal
  7. XML 标签xml:"name"xml:",attr"xml:",innerxml"

JSON 和 XML 是最常用的数据交换格式,掌握它们的处理是进行网络编程和数据处理的基础。在下一章中,我们将学习网络编程的基础知识。