Go语言解析含不同字段的JSON数组,提取首个元素的方法
问题分析与解决方法
核心问题
- 结构不匹配:你的JSON最外层是包含
Secrets数组的对象,但代码直接将整个JSON反序列化到model结构体,两者结构完全不匹配,导致所有字段都是零值,输出为空。 - Secret字段结构多样:
Secrets数组中不同元素的secret字段结构不同(一种包含tlsCertificate,另一种包含validationContext),需要兼容这两种结构。
解决步骤
1. 定义外层结构体匹配JSON结构
首先需要定义一个对应JSON最外层的结构体,用来承载Secrets数组:
type Response struct { Secrets []model `json:"Secrets"` }
2. 修改model兼容两种Secret结构
Go的JSON反序列化会忽略结构体中不存在的JSON字段,因此可以在Secret结构体中同时声明两种可能的字段:
type model struct { Name string `json:"name"` VersionInfo string `json:"versionInfo"` // 原格式带`/1`后缀,无法直接解析为time.Time,先存为字符串 LastUpdated time.Time `json:"lastUpdated"` Secret struct { Type string `json:"@type"` Name string `json:"name"` // 对应第一个元素的Secret结构 TLSCertificate struct { CertificateChain struct { InlineBytes string `json:"inlineBytes"` } `json:"certificateChain"` PrivateKey struct { InlineBytes string `json:"inlineBytes"` } `json:"privateKey"` } `json:"tlsCertificate"` // 对应第二个元素的Secret结构(仅用于兼容,不影响第一个元素的解析) ValidationContext struct { TrustedCa struct { InlineBytes string `json:"inlineBytes"` } `json:"trustedCa"` } `json:"validationContext"` } `json:"secret"` }
3. 修改反序列化逻辑,提取第一个元素
在main函数中先反序列化到外层结构体,再取出数组中的第一个元素:
func main() { input := []byte(jsondata) var resp Response err := json.Unmarshal(input, &resp) if err != nil { panic(err) } // 检查数组是否为空 if len(resp.Secrets) == 0 { fmt.Println("未找到任何Secrets数据") return } // 获取第一个元素并输出所需字段 firstSecret := resp.Secrets[0] fmt.Printf("名称: %s\n", firstSecret.Name) fmt.Printf("Secret名称: %s\n", firstSecret.Secret.Name) fmt.Printf("证书链: %s\n", firstSecret.Secret.TLSCertificate.CertificateChain.InlineBytes) fmt.Printf("私钥: %s\n", firstSecret.Secret.TLSCertificate.PrivateKey.InlineBytes) }
可选:将versionInfo解析为time.Time
如果需要把带/1后缀的versionInfo转为time.Time,可以自定义结构体的反序列化方法:
import "strings" func (m *model) UnmarshalJSON(data []byte) error { // 定义临时结构体用于临时存储数据 type tempModel struct { Name string `json:"name"` VersionInfo string `json:"versionInfo"` LastUpdated time.Time `json:"lastUpdated"` Secret struct { Type string `json:"@type"` Name string `json:"name"` TLSCertificate struct { CertificateChain struct { InlineBytes string `json:"inlineBytes"` } `json:"certificateChain"` PrivateKey struct { InlineBytes string `json:"inlineBytes"` } `json:"privateKey"` } `json:"tlsCertificate"` ValidationContext struct { TrustedCa struct { InlineBytes string `json:"inlineBytes"` } `json:"trustedCa"` } `json:"validationContext"` } `json:"secret"` } var t tempModel if err := json.Unmarshal(data, &t); err != nil { return err } // 截取`/`之前的时间字符串并解析 if idx := strings.Index(t.VersionInfo, "/"); idx != -1 { t.VersionInfo = t.VersionInfo[:idx] } versionTime, err := time.Parse(time.RFC3339, t.VersionInfo) if err != nil { return err } // 将临时结构体的数据赋值给原结构体 m.Name = t.Name m.VersionInfo = versionTime m.LastUpdated = t.LastUpdated m.Secret = t.Secret return nil }
此时将model中的VersionInfo类型改回time.Time即可:
VersionInfo time.Time `json:"versionInfo"`
内容的提问来源于stack exchange,提问作者user1513388
相关产品推荐
相关产品推荐

