将复数 JSON 中的每个值提取到 Swift 中的数组中

Extract every value from a complex JSON into an array in Swift

当后端发现错误时,我的客户return发疯了JSON。它包括许多 "errors" 键以及不确定数量的数组和 JSON 的嵌套部分。这是一个例子:

{
 "errors": {
    "children": {
      "name": {
        "errors": [
          "Error name"
        ]
      },
      "lastName": {
        "errors": [
          "Error lastName"
        ]
      },
      "email": {
        "errors": [
          "Error mail"
        ]
      },
      "gender": {},
      "birthday": {
        "children": {
          "year": {},
          "month": {
            "errors": [
              "Error month"
             ]
          },
          "day": {}
        }
      }
    }
  }
}

由于他声称无法将响应重写为 return 更常规的错误处理,我想遍历 JSON 并获取包含每个错误字符串的数组。鉴于除了错误没有其他价值,我认为获得所有价值也可以解决问题。 JSON 结构可能会根据错误位置和服务而改变。

我目前正在使用 SwiftyJSON 来解析响应(以防它可能有任何帮助)

假设您有一些数据

let data: Data = /* the way you get your JSON data */

您希望有一些函数可以从 JSON 中提取所有错误消息并将它们放入数组 [String] 中,不是吗?我在你的 JSON 中看到 4 个错误,所以让我们执行查找所有 4 条消息的函数:

func getErrors(_ dictionary: [String:JSON]?) -> [String] {
    guard let dictionary = dictionary else { return [] }
    let errorsNormal = dictionary
        .map({ (object) -> [String] in
            guard object.key == "errors" else { return [] }
            guard let array = object.value.array else { return [] }
            return  array.flatMap({ [=11=].string })
        })
        .flatMap({ [=11=] })
    let errorsRecursive = dictionary
        .flatMap({ (object) -> [String:JSON]? in
            return object.value.dictionary
        })
        .flatMap({ [=11=] })
        .map({ getErrors([=11=]) })
        .flatMap({ [=11=] })
    return errorsNormal + errorsRecursive
}

如何使用?

let errors = getErrors(json["errors"].dictionary)
debugPrint(errors)

日志将是

["Error lastName", "Error name", "Error mail", "Error month"]

P.S。如果这不是您想要的 - 请告诉我,我会删除答案

您可以编写一个递归函数,尝试从其输入中过滤掉错误消息。

由于您的 JSON 结构没有明确定义,您需要有条件地键入并检查您的根/当前对象作为数组或字典。

以下是可以在 XCode 游乐场中 运行 的示例代码。

func extractErrors(jsonObject: Any, errors: inout [String]) {
    if let array = jsonObject as? [Any] {
        array.forEach {
            extractErrors(jsonObject: [=10=], errors: &errors)
        }
    }
    else if let dict = jsonObject as? [String : Any] {
        for key in dict.keys {
            if key == "errors", let errorList = dict[key] as? [String] {
                errorList.forEach { errors.append([=10=]) }
            }
            else {
                extractErrors(jsonObject: dict[key]!, errors: &errors)
            }
        }
    }
}

let json = "{\"errors\":{\"children\":{\"name\":{\"errors\":[\"Error name\"]},\"lastName\":{\"errors\":[\"Error lastName\"]},\"email\":{\"errors\":[\"Error mail\"]},\"gender\":{},\"birthday\":{\"children\":{\"year\":{},\"month\":{\"errors\":[\"Error month\"]},\"day\":{}}}}}}"

if let data = json.data(using: .utf8),
    let jsonObject = try? JSONSerialization.jsonObject(with: data, options: [.mutableContainers])
{
    var errors = [String]()
    extractErrors(jsonObject: jsonObject, errors: &errors)
    print(errors) // ["Error lastName", "Error name", "Error mail", "Error month"]

}