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

时间:2017-04-30 04:34:15

标签: json swift nsdictionary flatten

当后端发现错误时,我的客户端正在返回疯狂的JSON。它包含许多“错误”键,沿着不确定数量的数组和JSON的嵌套部分。这是一个例子:

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

由于他声称无法重写响应以返回更常规的错误处理,因此我想迭代JSON并获取包含每个错误字符串的数组。鉴于除了错误之外没有其他价值,我认为获得所有价值也会起到作用。 JSON结构可能会根据错误位置和服务而更改。

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

2 个答案:

答案 0 :(得分:3)

让我们说你有一些数据

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({ $0.string })
        })
        .flatMap({ $0 })
    let errorsRecursive = dictionary
        .flatMap({ (object) -> [String:JSON]? in
            return object.value.dictionary
        })
        .flatMap({ $0 })
        .map({ getErrors($0) })
        .flatMap({ $0 })
    return errorsNormal + errorsRecursive
}

如何使用?

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

日志将是

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

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

答案 1 :(得分:1)

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

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

以下是可以在XCode Playground中运行的示例代码。

func extractErrors(jsonObject: Any, errors: inout [String]) {
    if let array = jsonObject as? [Any] {
        array.forEach {
            extractErrors(jsonObject: $0, 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($0) }
            }
            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"]

}