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

Swift中JSON动态解析:如何根据start字段值获取对应嵌套对象

动态适配JSON中基于start字段的嵌套内容解析(Swift Codable实现)

原始JSON片段

"journey": {
    "start": "The6422Dcd89Dc070B243Da5743",
    "6422dcd89dc070b243da5743": {
        "events": [
            {
                "event_id": "4af5dbc5-b8ae-492d-aa97-16bb9b0967c9",
                "type": "sale",
                "name": "SALE"
            }
        ]
    }
}

现有硬编码结构体

// MARK: - Journey
struct Journey: Codable {
    let start: String?
    let value: The6422Dcd89Dc070B243Da5743?
    let summary: [Summary]?
    enum CodingKeys: String, CodingKey {
        case start
        case value = "6422dcd89dc070b243da5743"
        case summary
    }
}

解决方案:自定义解码逻辑实现动态适配

要实现动态匹配start字段对应的嵌套内容,需要自定义Codable的解码方法,结合动态CodingKey处理可变键名。

完整实现代码

// MARK: - Journey
struct Journey: Codable {
    let start: String?
    let value: JourneyContent?
    let summary: [Summary]?
    
    init(from decoder: Decoder) throws {
        // 解析固定字段start和summary
        let container = try decoder.container(keyedBy: CodingKeys.self)
        start = try container.decodeIfPresent(String.self, forKey: .start)
        summary = try container.decodeIfPresent([Summary].self, forKey: .summary)
        
        // 处理动态匹配的嵌套内容
        guard let startValue = start else {
            value = nil
            return
        }
        // 转换start值以匹配JSON中的键:去掉前缀"The"并转为小写
        let dynamicKeyString = startValue.lowercased().replacingOccurrences(of: "the", with: "")
        let dynamicKey = AnyCodingKey(stringValue: dynamicKeyString)
        
        // 用动态键解析对应内容
        let dynamicContainer = try decoder.container(keyedBy: AnyCodingKey.self)
        value = try dynamicContainer.decodeIfPresent(JourneyContent.self, forKey: dynamicKey)
    }
    
    enum CodingKeys: String, CodingKey {
        case start, summary
    }
    
    // 自定义CodingKey,支持任意字符串键
    private struct AnyCodingKey: CodingKey {
        var stringValue: String
        var intValue: Int?
        
        init(stringValue: String) {
            self.stringValue = stringValue
        }
        
        init?(intValue: Int) {
            self.intValue = intValue
            self.stringValue = String(intValue)
        }
    }
}

// 通用的嵌套内容结构体,替代原固定命名结构体
struct JourneyContent: Codable {
    let events: [Event]?
}

// Event结构体保持原有解码逻辑
struct Event: Codable {
    let eventId: String?
    let type: String?
    let name: String?
    
    enum CodingKeys: String, CodingKey {
        case eventId = "event_id"
        case type, name
    }
}

// Summary结构体根据实际需求定义字段
struct Summary: Codable {
    // 示例字段,按需修改
    let id: String?
}

关键逻辑说明

  • 动态CodingKey:定义AnyCodingKey结构体,允许使用任意字符串作为解码键,摆脱硬编码限制。
  • 自定义解码流程:在init(from decoder: Decoder)中,先解析固定字段start和summary,再通过start的值转换得到动态键,进而解析对应的嵌套内容。
  • 结构复用:将原固定命名的嵌套结构体替换为通用的JourneyContent,适配所有同类结构的动态键内容。

解码测试示例

let testJson = """
{
    "journey": {
        "start": "The6422Dcd89Dc070B243Da5743",
        "6422dcd89dc070b243da5743": {
            "events": [
                {
                    "event_id": "4af5dbc5-b8ae-492d-aa97-16bb9b0967c9",
                    "type": "sale",
                    "name": "SALE"
                }
            ]
        },
        "summary": [{"id": "sum_001"}]
    }
}
"""

do {
    let data = testJson.data(using: .utf8)!
    let decoded = try JSONDecoder().decode([String: Journey].self, from: data)
    guard let journey = decoded["journey"] else { return }
    
    print("Start标识:\(journey.start ?? "无")")
    print("事件数量:\(journey.value?.events?.count ?? 0)")
    print("Summary数量:\(journey.summary?.count ?? 0)")
} catch {
    print("解码失败:\(error.localizedDescription)")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:24:57