Golang处理稍复杂JSON数据的实用技巧

Golang处理稍复杂JSON数据的实用技巧 在处理复杂的JSON结构时,我似乎无法从json.Unmarshal得到任何返回结果。

以下是来自Shopify API的响应示例:

{“products”:[{“id”:2570195271760,“title”:“Sample Product”,“body_html”:“Example of an html body”}]}

我尝试了以下方法:

    Resio, _ := ioutil.ReadAll(res.Body)

    JSONProducts := string(Resio)

    type Product struct {

        Id string `json:"id"`

    }

    type Response struct {

        Products []Product `json:"products"`

    }

    ProductsList := Response{}

    json.Unmarshal([]byte(JSONProducts), &ProductsList)

    fmt.Println(ProductsList.Products)

    fmt.Println(ProductsList)

但我的响应看起来像这样:

[{}] {[{}]}

我哪里做错了?


更多关于Golang处理稍复杂JSON数据的实用技巧的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

谢谢!非常清晰的解决方案。

更多关于Golang处理稍复杂JSON数据的实用技巧的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这段代码看起来与我用来解析一个相当复杂JSON文件的代码几乎完全相同,但我会尝试将 titlebody_html 元素添加到 Product 结构体中,看看是否有所不同(不过按理说不应该,因为我的代码也没有使用所有元素)。同时,打印 JSONProducts 字符串以确保该字符串包含你期望的内容。

type Product struct {

        Id string `json:"id"`
        Title     `json:"title"`
        BodyHtml  `json:"body_html"
    }

由于JSON输入中的id属性是JSON数字类型,因此无法将其反序列化为Go的string类型。请将Id的类型更改为int64,并添加另外两个属性:

type Product struct {
	Id    int64  `json:"id"`
	Title string `json:"title"`
	Body  string `json:"body_html"`
}

查看此链接获取可运行的示例。

该代码的输出为:

[{2570195271760 Sample Product Example of an html body}]
{[{2570195271760 Sample Product Example of an html body}]}

你的问题在于JSON中的id字段是数值类型(2570195271760),而你在Go结构体中将其定义为string类型。json.Unmarshal在类型不匹配时不会报错,而是会保留字段的零值(对于字符串就是空字符串)。

以下是修正后的代码:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
)

func main() {
    // 模拟API响应数据
    jsonData := `{"products":[{"id":2570195271760,"title":"Sample Product","body_html":"Example of an html body"}]}`

    type Product struct {
        ID       int64  `json:"id"`      // 改为int64类型
        Title    string `json:"title,omitempty"`
        BodyHTML string `json:"body_html,omitempty"`
    }

    type Response struct {
        Products []Product `json:"products"`
    }

    var response Response
    err := json.Unmarshal([]byte(jsonData), &response)
    if err != nil {
        fmt.Println("解析错误:", err)
        return
    }

    fmt.Printf("完整响应: %+v\n", response)
    fmt.Printf("产品列表: %+v\n", response.Products)
    
    // 访问第一个产品
    if len(response.Products) > 0 {
        fmt.Printf("产品ID: %d\n", response.Products[0].ID)
        fmt.Printf("产品标题: %s\n", response.Products[0].Title)
    }
}

如果你确实需要将ID保持为字符串类型,可以在结构体中使用json.Number类型:

type Product struct {
    ID       json.Number `json:"id"`  // 使用json.Number
    Title    string      `json:"title,omitempty"`
    BodyHTML string      `json:"body_html,omitempty"`
}

// 使用时可以转换为字符串或数值
idStr := product.ID.String()
idInt, _ := product.ID.Int64()

或者使用interface{}类型配合类型断言:

type Product struct {
    ID       interface{} `json:"id"`
    Title    string      `json:"title,omitempty"`
    BodyHTML string      `json:"body_html,omitempty"`
}

// 使用时进行类型判断
switch v := product.ID.(type) {
case float64:
    fmt.Printf("数值ID: %.0f\n", v)
case string:
    fmt.Printf("字符串ID: %s\n", v)
}

对于更复杂的JSON处理,可以考虑以下技巧:

  1. 使用json.RawMessage延迟解析
type Response struct {
    Products json.RawMessage `json:"products"`
}

var response Response
json.Unmarshal(data, &response)

// 稍后根据需要解析products
var products []Product
json.Unmarshal(response.Products, &products)
  1. 处理动态字段
type Product struct {
    ID    int64                  `json:"id"`
    Extra map[string]interface{} `json:"-"` // 忽略已知字段外的其他字段
}

func (p *Product) UnmarshalJSON(data []byte) error {
    type Alias Product
    aux := &struct {
        *Alias
    }{
        Alias: (*Alias)(p),
    }
    
    if err := json.Unmarshal(data, &aux); err != nil {
        return err
    }
    
    // 提取额外字段
    var m map[string]interface{}
    json.Unmarshal(data, &m)
    delete(m, "id")
    p.Extra = m
    
    return nil
}
  1. 使用指针字段处理可选字段
type Product struct {
    ID       *int64  `json:"id,omitempty"` // 使用指针,nil表示字段不存在
    Title    *string `json:"title,omitempty"`
}

// 检查字段是否存在
if product.ID != nil {
    fmt.Printf("ID存在: %d\n", *product.ID)
}

确保始终检查json.Unmarshal返回的错误,这能帮助你快速定位解析问题。

回到顶部