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
相关产品推荐
相关产品推荐

