FunctionalJSON是Swift的一个快速、函数式JSON库。
灵感来源于play/scala JSON库。
json
{
"customers" : [
{
"name" : "alice",
"age" : 20,
"transactions" : [{"id" : 21312},{"id" : 32414},{"id" : 23443}]
},
{
"name" : "bob",
"transactions" : []
},
{
"name" : "chris",
"age" : 34,
"transactions" : [{"id" : 23455},{"id" : 23452}]
}
]
}
swift
import FunctionalJSON
import FunctionalBuilder
struct Person : JSONReadable {
let name : String
let age : Int?
let transactions : [Transaction]
static let jsonRead = JSONRead(
JSONPath("name").read(String) <&>
JSONPath("age").read(Int?) <&>
JSONPath("transactions").read([Transaction])
).map(Person.init)
}
struct Transaction : JSONReadable {
let identifier : Int64
static let jsonRead = JSONPath("id").read(Int64).map(Transaction.init)
}
let jsonData : NSData = ...
let json = try JSONValue(data : jsonData)
let persons : [Person] = try json["customers"].validate([Person])
结构体JSONValue
包含解析的JSON数据。
let jsonData : NSData = ...
let json = try JSONValue(data : jsonData)
输入数据使用Foundation NSJSONSerialization进行解析。
可以将解析选项作为初始化参数传递
let json = try JSONValue(data: jsonData, options : [.AllowFragments])
使用中括号和JSONPath
进行导航
let jsonElement : JSONValue = json[JSONPath("customers",0)]
或
let jsonElement : JSONValue = json["customers"][0] <br />
或
let jsonElement : JSONValue = json["customers",0]
JSONPath
是JSONPathComponent
数组的外包装器
public enum JSONPathComponent {
case Key(String)
case Index(Int)
}
一个Key
值代表JSON对象的键,一个Index
代表JSON数组中的索引。
此方法始终返回一个JSONValue
,即使JSON树中没有相应的值。
isNull
属性将在没有值时返回true
。
let isNull : Bool = json["customers",1992002].isNull
isEmpty
属性将在没有底层值或是一个空对象或数组时返回true
。
let isEmpty : Bool = json["customers"].isEmpty
结构体JSONRead<T>
定义了从JSON中读取值的方式。它包含元素路径和将元素验证和转换为类型T
的的目标值的函数。
所有基本JSON类型都已实现并映射到Swift类型。(Int..
,Double
,Float
,String
,Array
)
JSONRead
可以用以下方式进行转换:
map<U>(t : T throws -> U) -> JSONRead<U>
“customers”/0/“age”
处读取一个Int
值let read : JSONRead<Int> = JSONPath(["customers",0,"age"]).read(Int)
let readDate : JSONRead<NSDate> = read.map {
guard let date = NSCalendar.currentCalendar().dateByAddingUnit(.Year,
value: -$0,
toDate: NSDate(),
options: []) else {
throw Error.DateError
}
return date
}
let optionalRead : JSONRead<NSDate?> = readDate.optional
let defaultDateRead : JSONRead<NSDate> = readDate.withDefault(NSDate())
let jsonValue : JSONValue = ...
do {
let date : NSDate = try jsonValue.validate(defaultDateRead)
} catch {
...
}
public protocol JSONReadable {
static var jsonRead : JSONRead<Self> {get}
}
JSONReadable
协议用于获取类型的默认读取操作。它不能应用于非最终 class
,因为子类无法重新声明其类型的 jsonRead 静态变量。
此协议使得在 JSONValue
验证和 JSONPath
读取方法中启用“类型”语法。
JSONPath("name").read(String)
而不是
JSONPath("name").read(String.jsonRead)
组合和 <&
操作符来自 FunctionalBuilder
模块。该模块用于组合泛型抛出函数并累积错误。您可以组合多达 10 次读取。
let read : JSONRead<(String,Int?,[Transaction])> = JSONRead(
JSONPath("name").read(String) <&>
JSONPath("age").read(Int?) <&>
JSONPath("transactions").read([Transaction])
)
与其他 json 库不同,验证不会在第一个错误处停止。相反,所有错误都会累积并最终以错误列表的形式报告出来。
使用前几次读取验证此 JSON
{
"name" : 31232,
"age" : 30,
"transactions" : [{"identifier" : 23455},{"id" : 23455}]
}
let json = try JSONValue(data : jsonData)
do {
try json.validate(Person)
} catch {
print(error)
}
这将抛出一个包含 2 个错误的 JSONValidationError
异常。
JSON Errors :
JSON Bad value type -> "name"
JSON Value not found -> "transactions/0/id"