You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift JSON Decoder解析混合结构数组问题求助

问题描述

给定如下不规则JSON结构:

[
    {
        "texts": [
            {
                "value": "value 1"
            }
        ],
        "commentType": "someComment"
    },
    {
        "texts": [
            {
                "value": "value 2"
            }
        ],
        "commentType": "someComment2"
    },
    {
        "texts": [
            {
                "evidences": [
                    {
                        "evidenceCode": "code 1"
                    },
                    {
                        "evidenceCode": "code 2"
                    },
                    {
                        "evidenceCode": "code 3"
                    },
                    {
                        "evidenceCode": "code 4"
                    }
                ],
                "value": "value 3"
            }
        ],
        "commentType": "someComment3"
    }
]

现有解析代码可处理前两个texts字段和commentType,代码如下:

enum CodingKeys: String, CodingKey {
    case texts
    case commentType
}

do {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let name = try container.decode(String.self, forKey: .commentType)
    
    if let texts = try container.decodeIfPresent([[String: String]].self, forKey: .texts) {
        for text in texts {
            if let value = text["value"] {
                // add to model object
            }
        }
    }
} catch {
    print(error)
}

但解析第三个texts块时触发错误:

"Expected to decode String but found an array instead."

原因是第三个texts内的元素并非纯[String:String]结构,而是包含evidences数组与value字段的混合结构,需调整解析逻辑提取value 3。

解决方案

不要直接用[[String: String]]解码texts,自定义TextItem类型处理混合结构,通过自定义init(from decoder: Decoder)方法兼容两种情况:

// 定义对应JSON结构的模型
struct Comment: Decodable {
    let commentType: String
    let texts: [TextItem]
}

struct TextItem: Decodable {
    let value: String
    let evidences: [Evidence]? // 可选字段,对应第三个item的evidences
    
    struct Evidence: Decodable {
        let evidenceCode: String
    }
    
    enum CodingKeys: String, CodingKey {
        case value, evidences
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 强制解析value字段,所有textItem均包含该字段
        self.value = try container.decode(String.self, forKey: .value)
        // 尝试解析evidences,无该字段则设为nil
        self.evidences = try container.decodeIfPresent([Evidence].self, forKey: .evidences)
    }
}

// 解析调用示例
do {
    let comments = try JSONDecoder().decode([Comment].self, from: yourJsonData)
    for comment in comments {
        print("CommentType: \(comment.commentType)")
        for textItem in comment.texts {
            print("Value: \(textItem.value)")
            // 若存在evidences可额外处理
            if let evidences = textItem.evidences {
                print("Evidences: \(evidences.map(\.evidenceCode))")
            }
        }
    }
} catch {
    print(error)
}

逻辑说明

  1. 外层Comment模型对应JSON的顶层结构,包含commentType和texts数组
  2. TextItem模型包含必填的value和可选的evidences,自定义解码方法确保无论是否存在evidences数组,都能正确提取value
  3. 该方式同时兼容前两个无evidences的texts元素,以及第三个带evidences的元素,避免类型不匹配错误

内容的提问来源于stack exchange,提问作者koen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 21:25:34