Golang 中 JSON 和 XML 解析与生成

JSON 处理

JSON 解析

在 Go 语言中,encoding/json 包提供了强大的 JSON 处理能力。JSON 解析主要有两种方式:

  1. 解析到结构体(推荐方式):
type Person struct {
    Name    string `json:"name"`  // 使用标签指定 JSON 字段名
    Age     int    `json:"age"`
    Address string `json:"address,omitempty"` // omitempty 表示字段为空时忽略
}

func main() {
    jsonStr := `{"name":"张三","age":30}`
    var p Person
    
    err := json.Unmarshal([]byte(jsonStr), &p)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("%+v\n", p) // 输出: {Name:张三 Age:30 Address:}
}

  1. 解析到 map(适用于动态结构):
func main() {
    jsonStr := `{"name":"李四","age":25,"hobbies":["reading","swimming"]}`
    var data map[string]interface{}
    
    err := json.Unmarshal([]byte(jsonStr), &data)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println(data["name"]) // 输出: 李四
    fmt.Println(data["hobbies"].([]interface{})[0]) // 输出: reading
}

JSON 生成

将 Go 数据结构转为 JSON 同样简单:

func main() {
    p := Person{
        Name: "王五",
        Age:  28,
    }
    
    jsonData, err := json.Marshal(p)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println(string(jsonData)) // 输出: {"name":"王五","age":28}
    
    // 格式化输出
    jsonData, _ = json.MarshalIndent(p, "", "  ")
    fmt.Println(string(jsonData))
    /*
    输出:
    {
      "name": "王五",
      "age": 28
    }
    */
}

XML 处理

XML 解析

Go 标准库中的 encoding/xml 包提供了 XML 处理功能:

  1. 解析到结构体
type Employee struct {
    XMLName   xml.Name `xml:"employee"`
    ID        int      `xml:"id,attr"`      // 解析为属性
    FirstName string   `xml:"name>first"`   // 嵌套元素
    LastName  string   `xml:"name>last"`
    Position  string   `xml:"position"`
    Salary    float64  `xml:"salary"`
}

func main() {
    xmlStr := `
    <employee id="1001">
        <name>
            <first>诸葛</first>
            <last>亮</last>
        </name>
        <position>丞相</position>
        <salary>9999.99</salary>
    </employee>`
    
    var emp Employee
    err := xml.Unmarshal([]byte(xmlStr), &emp)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("%+v\n", emp) // 输出: {XMLName:{Space: Local:employee} ID:1001 FirstName:诸葛 LastName:亮 Position:丞相 Salary:9999.99}
}

  1. 流式解析(适用于大文件):
func main() {
    xmlFile, err := os.Open("employees.xml")
    if err != nil {
        log.Fatal(err)
    }
    defer xmlFile.Close()
    
    decoder := xml.NewDecoder(xmlFile)
    for {
        // 逐个解析 token
        t, err := decoder.Token()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        
        switch se := t.(type) {
        case xml.StartElement:
            if se.Name.Local == "employee" {
                var emp Employee
                decoder.DecodeElement(&emp, &se)
                fmt.Println(emp)
            }
        }
    }
}

XML 生成

将 Go 结构体转为 XML:

func main() {
    emp := Employee{
        ID:        1002,
        FirstName: "周",
        LastName:  "瑜",
        Position:  "都督",
        Salary:    8888.88,
    }
    
    xmlData, err := xml.MarshalIndent(emp, "", "  ")
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println(string(xmlData))
    /*
    输出:
    <employee id="1002">
      <name>
        <first>周</first>
        <last>瑜</last>
      </name>
      <position>都督</position>
      <salary>8888.88</salary>
    </employee>
    */
    
    // 添加 XML 头
    xmlData = []byte(xml.Header + string(xmlData))
    fmt.Println(string(xmlData))
}

实际应用场景

  1. Web API 开发:
  • 接收请求数据:
    • 处理客户端发送的 JSON/XML 格式的 HTTP 请求
    • 使用标准库或第三方库(如 encoding/json、encoding/xml)解析请求体
    • 示例:解析用户注册请求 {"username":"test","password":"123456"}
  • 返回响应:
    • 将业务数据序列化为 JSON/XML 格式响应
    • 设置正确的 Content-Type 响应头(application/json 或 application/xml)
    • 示例:返回用户信息 {"id":1,"name":"张三","age":25}
  1. 配置文件处理:
  • 解析配置文件:
    • 读取项目的 config.json/config.xml 文件
    • 解析为配置结构体供程序使用
    • 支持热更新配置(监听文件变化自动重新加载)
  • 备份配置:
    • 定期将当前配置序列化为 JSON/XML 格式备份
    • 支持版本控制(如 config_v1.json, config_v2.json)
  1. 数据交换:
  • 系统间通信:
    • 通过 HTTP/RPC 等方式在微服务间传递 JSON/XML 数据
    • 定义统一的数据交换格式规范
  • 第三方 API 集成:
    • 对接微信支付、支付宝等第三方平台的 API
    • 处理不同格式的请求/响应(如微信使用 XML,支付宝使用 JSON)
  1. 数据持久化:
  • 数据存储:
    • 将内存中的数据结构序列化为 JSON/XML 保存到本地文件
    • 支持压缩存储以减少磁盘空间占用
  • 数据恢复:
    • 从存储文件中读取数据并反序列化
    • 处理数据版本兼容性问题

性能优化建议

  1. 处理大型数据:
  • 流式处理:
    • 使用 json.Decoder 逐步解析大型 JSON 文件
    • 使用 xml.Decoder 处理 XML 数据流
    • 避免一次性加载整个文件导致内存溢出
  • 示例代码:
    decoder := json.NewDecoder(largeFile)
    for decoder.More() {
        var item DataItem
        if err := decoder.Decode(&item); err != nil {
            // 处理错误
        }
        // 处理item
    }
    

  1. 实例复用:
  • 编码器复用:
    • 在 HTTP 服务中复用全局的 json.Encoder 实例
    • 通过 sync.Pool 管理编码器对象池
  • 解码器复用:
    • 对高频请求创建长期存活的解码器实例
    • 避免重复创建带来的性能损耗
  1. 第三方库优化:
  • jsoniter:
    • 替换标准库实现,提升 2-3 倍性能
    • 支持流式处理和大数据量场景
    • 示例:
      import "github.com/json-iterator/go"
      var json = jsoniter.ConfigCompatibleWithStandardLibrary
      

  • 其他优化库:
    • fastjson 用于极致性能场景
    • easyjson 通过代码生成优化
  1. 内存优化:
  • 原始字节操作:
    • 使用 json.RawMessage 延迟解析
    • 直接操作 JSON 字节数据避免完整反序列化
    • 示例:
      type Message struct {
          Header json.RawMessage
          Body   json.RawMessage
      }
      

  • 内存池技术:
    • 使用 sync.Pool 重用缓冲区
    • 减少 GC 压力

常见问题处理

  1. 处理动态字段
type DynamicData struct {
    Data map[string]interface{} `json:",inline"` // 处理未知字段
}

  1. 自定义时间格式
type Event struct {
    Time CustomTime `json:"time"`
}

type CustomTime struct {
    time.Time
}

func (ct *CustomTime) UnmarshalJSON(b []byte) error {
    s := strings.Trim(string(b), `"`)
    t, err := time.Parse("2006-01-02 15:04:05", s)
    if err != nil {
        return err
    }
    ct.Time = t
    return nil
}

func (ct CustomTime) MarshalJSON() ([]byte, error) {
    return []byte(`"` + ct.Time.Format("2006-01-02 15:04:05") + `"`), nil
}

  1. 处理特殊字符
// 在 XML 中处理 CDATA
type Description struct {
    Content string `xml:",cdata"`
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐