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

Swift Decodable:能否将JSON部分节点读取为字符串而非数据结构?

Swift Codable 解析JSON时将指定节点转为字符串

要实现把JSON中的def节点(JSON对象)直接读取为字符串,不能直接用decode(String.self)(因为该节点是JSON对象而非原生字符串类型),可以通过先将节点解码为任意JSON对象,再序列化为Data后转成字符串的方式实现,完整代码如下:

import Foundation

let json = #"""
{
    "abc": 123,
    "def": {
        "xyz": "hello world!"
    }
}
"""#

// 自定义类型,用于解码任意JSON对象(支持嵌套结构)
private struct JSONObject: Decodable {
    let value: Any
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        
        // 依次兼容解析不同类型的JSON值
        if let intValue = try? container.decode(Int.self) {
            value = intValue
        } else if let stringValue = try? container.decode(String.self) {
            value = stringValue
        } else if let boolValue = try? container.decode(Bool.self) {
            value = boolValue
        } else if let doubleValue = try? container.decode(Double.self) {
            value = doubleValue
        } else if let arrayValue = try? container.decode([JSONObject].self) {
            value = arrayValue.map { $0.value }
        } else if let dictValue = try? container.decode([String: JSONObject].self) {
            value = dictValue.mapValues { $0.value }
        } else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "无法解析该JSON节点")
        }
    }
}

struct X: Decodable {
    let abc: Int
    let def: String

    enum CodingKeys: String, CodingKey {
        case abc
        case def
    }

    init(decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 正常解析abc字段
        abc = try container.decode(Int.self, forKey: .abc)
        
        // 处理def字段:先解码为JSON对象,再转回JSON格式字符串
        let defObject = try container.decode(JSONObject.self, forKey: .def)
        let defData = try JSONSerialization.data(withJSONObject: defObject.value, options: [])
        guard let defString = String(data: defData, encoding: .utf8) else {
            throw DecodingError.dataCorruptedError(forKey: .def, in: container, debugDescription: "无法将JSON节点转换为字符串")
        }
        def = defString
    }
}

// 测试解析逻辑
do {
    let x = try JSONDecoder().decode(X.self, from: json.data(using: .utf8)!)
    print(x.abc) // 输出:123
    print(x.def) // 输出:{"xyz":"hello world!"}
} catch {
    print(error)
}

关键说明

  • 自定义JSONObject类型:兼容解析所有JSON基础类型及嵌套结构,将其转为Any类型保存,确保能处理任意复杂的JSON节点。
  • 字符串转换逻辑:通过JSONSerialization将解码后的JSON对象重新序列化为Data,再转为字符串,保证输出的是标准JSON格式字符串。
  • 格式化输出可选:如果需要带缩进的格式化JSON字符串,可将JSONSerialization.data的options参数改为.prettyPrinted。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:20:29