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

Swift:如何声明可匹配任意JSON的递归节点类型?

一、让结构体支持任意JSON的实现方式

原代码中的xsd是强类型固定字段结构体,要匹配任意结构的JSON,推荐两种方案:

方案1:直接解析为动态字典(快速实现)

利用JSONSerialization将JSON数据转为[String: Any]或Any,可处理任意JSON结构:

do {
    if let jsonURL = Bundle.main.url(forResource: "user", withExtension: "json") {
        let jsonData = try Data(contentsOf: jsonURL)
        let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
        // 根据实际类型处理数据
        if let userDict = jsonObject as? [String: Any] {
            print(userDict)
        } else if let userArray = jsonObject as? [Any] {
            print(userArray)
        }
    }
} catch {
    print("解析错误:\(error)")
}

方案2:定义类型安全的递归JSON枚举(推荐)

自定义遵循Decodable的枚举,覆盖JSON所有可能类型,既支持任意结构又保持类型安全:

enum JSONValue: Decodable {
    case string(String)
    case number(Double)
    case boolean(Bool)
    case null
    case object([String: JSONValue])
    case array([JSONValue])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let str = try? container.decode(String.self) {
            self = .string(str)
        } else if let num = try? container.decode(Double.self) {
            self = .number(num)
        } else if let bool = try? container.decode(Bool.self) {
            self = .boolean(bool)
        } else if container.decodeNil() {
            self = .null
        } else if let obj = try? container.decode([String: JSONValue].self) {
            self = .object(obj)
        } else if let arr = try? container.decode([JSONValue].self) {
            self = .array(arr)
        } else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "无法解析为合法JSON类型")
        }
    }
}

// 使用示例
do {
    if let jsonURL = Bundle.main.url(forResource: "user", withExtension: "json") {
        let jsonData = try Data(contentsOf: jsonURL)
        let json = try JSONDecoder().decode(JSONValue.self, from: jsonData)
        print(json)
        // 按需访问嵌套字段
        if case .object(let dict) = json, case .string(let name) = dict["name"] {
            print("用户名:\(name)")
        }
    }
} catch {
    print("解析错误:\(error)")
}
二、定义递归的JSON节点结构

参考HTML Node的设计思路,我们可以创建一个支持递归嵌套的JSONNode结构,覆盖所有JSON类型:

public struct JSONNode {
    public enum NodeType {
        case string(String)
        case number(Double)
        case boolean(Bool)
        case null
        case object([String: JSONNode]) // 对象值为JSONNode,支持递归嵌套
        case array([JSONNode])          // 数组元素为JSONNode,支持递归嵌套
    }

    public let type: NodeType

    // 便捷初始化方法,简化节点创建
    public init(string value: String) {
        self.type = .string(value)
    }

    public init(number value: Double) {
        self.type = .number(value)
    }

    public init(boolean value: Bool) {
        self.type = .boolean(value)
    }

    public init(null: Void) {
        self.type = .null
    }

    public init(object value: [String: JSONNode]) {
        self.type = .object(value)
    }

    public init(array value: [JSONNode]) {
        self.type = .array(value)
    }
}

// 构建嵌套JSON节点示例
let userNode = JSONNode(object: [
    "name": JSONNode(string: "张三"),
    "age": JSONNode(number: 28),
    "isActive": JSONNode(boolean: true),
    "address": JSONNode(object: [
        "city": JSONNode(string: "北京"),
        "street": JSONNode(string: "某某街道")
    ]),
    "hobbies": JSONNode(array: [
        JSONNode(string: "读书"),
        JSONNode(string: "跑步")
    ])
])

如果需要让JSONNode支持编码/解码,可参考前面JSONValue的实现,让其遵循Codable协议。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 02:50:34