|
|
@@ -1,1245 +0,0 @@
|
|
|
-// SwiftyJSON.swift
|
|
|
-//
|
|
|
-// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
|
|
|
-//
|
|
|
-// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
-// of this software and associated documentation files (the "Software"), to deal
|
|
|
-// in the Software without restriction, including without limitation the rights
|
|
|
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
-// copies of the Software, and to permit persons to whom the Software is
|
|
|
-// furnished to do so, subject to the following conditions:
|
|
|
-//
|
|
|
-// The above copyright notice and this permission notice shall be included in
|
|
|
-// all copies or substantial portions of the Software.
|
|
|
-//
|
|
|
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
-// THE SOFTWARE.
|
|
|
-
|
|
|
-import Foundation
|
|
|
-
|
|
|
-// MARK: - Error
|
|
|
-
|
|
|
-///Error domain
|
|
|
-public let ErrorDomain: String = "SwiftyJSONErrorDomain"
|
|
|
-
|
|
|
-///Error code
|
|
|
-public let ErrorUnsupportedType: Int = 999
|
|
|
-public let ErrorIndexOutOfBounds: Int = 900
|
|
|
-public let ErrorWrongType: Int = 901
|
|
|
-public let ErrorNotExist: Int = 500
|
|
|
-public let ErrorInvalidJSON: Int = 490
|
|
|
-
|
|
|
-// MARK: - JSON Type
|
|
|
-
|
|
|
-/**
|
|
|
-JSON's type definitions.
|
|
|
-
|
|
|
-See http://www.json.org
|
|
|
-*/
|
|
|
-public enum Type :Int{
|
|
|
-
|
|
|
- case number
|
|
|
- case string
|
|
|
- case bool
|
|
|
- case array
|
|
|
- case dictionary
|
|
|
- case null
|
|
|
- case unknown
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - JSON Base
|
|
|
-
|
|
|
-public struct JSON {
|
|
|
-
|
|
|
- /**
|
|
|
- Creates a JSON using the data.
|
|
|
-
|
|
|
- - parameter data: The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
|
|
|
- - parameter opt: The JSON serialization reading options. `.AllowFragments` by default.
|
|
|
- - parameter error: error The NSErrorPointer used to return the error. `nil` by default.
|
|
|
-
|
|
|
- - returns: The created JSON
|
|
|
- */
|
|
|
- public init(data:Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer? = nil) {
|
|
|
- do {
|
|
|
- let object: Any = try JSONSerialization.jsonObject(with: data, options: opt)
|
|
|
- self.init(object)
|
|
|
- } catch let aError as NSError {
|
|
|
- if error != nil {
|
|
|
- error??.pointee = aError
|
|
|
- }
|
|
|
- self.init(NSNull())
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- Create a JSON from JSON string
|
|
|
- - parameter string: Normal json string like '{"a":"b"}'
|
|
|
-
|
|
|
- - returns: The created JSON
|
|
|
- */
|
|
|
- public static func parse(_ string:String) -> JSON {
|
|
|
- return string.data(using: String.Encoding.utf8)
|
|
|
- .flatMap({JSON(data: $0)}) ?? JSON(NSNull())
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- Creates a JSON using the object.
|
|
|
-
|
|
|
- - parameter object: The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
|
|
|
-
|
|
|
- - returns: The created JSON
|
|
|
- */
|
|
|
- public init(_ object: Any) {
|
|
|
- self.object = object
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- Creates a JSON from a [JSON]
|
|
|
-
|
|
|
- - parameter jsonArray: A Swift array of JSON objects
|
|
|
-
|
|
|
- - returns: The created JSON
|
|
|
- */
|
|
|
- public init(_ jsonArray:[JSON]) {
|
|
|
- self.init(jsonArray.map { $0.object })
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- Creates a JSON from a [String: JSON]
|
|
|
-
|
|
|
- - parameter jsonDictionary: A Swift dictionary of JSON objects
|
|
|
-
|
|
|
- - returns: The created JSON
|
|
|
- */
|
|
|
- public init(_ jsonDictionary:[String: JSON]) {
|
|
|
- var dictionary = [String: Any](minimumCapacity: jsonDictionary.count)
|
|
|
- for (key, json) in jsonDictionary {
|
|
|
- dictionary[key] = json.object
|
|
|
- }
|
|
|
- self.init(dictionary)
|
|
|
- }
|
|
|
-
|
|
|
- /// fileprivate object
|
|
|
- fileprivate var rawArray: [Any] = []
|
|
|
- fileprivate var rawDictionary: [String : Any] = [:]
|
|
|
- fileprivate var rawString: String = ""
|
|
|
- fileprivate var rawNumber: NSNumber = 0
|
|
|
- fileprivate var rawNull: NSNull = NSNull()
|
|
|
- fileprivate var _type: Type = .null
|
|
|
- fileprivate var _error: NSError? = nil
|
|
|
-
|
|
|
- /// Object in JSON
|
|
|
- public var object: Any {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .array:
|
|
|
- return self.rawArray
|
|
|
- case .dictionary:
|
|
|
- return self.rawDictionary
|
|
|
- case .string:
|
|
|
- return self.rawString
|
|
|
- case .number:
|
|
|
- return self.rawNumber
|
|
|
- case .bool:
|
|
|
- return self.rawNumber
|
|
|
- default:
|
|
|
- return self.rawNull
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- _error = nil
|
|
|
- switch newValue {
|
|
|
- case let number as NSNumber:
|
|
|
- if number.isBool {
|
|
|
- _type = .bool
|
|
|
- } else {
|
|
|
- _type = .number
|
|
|
- }
|
|
|
- self.rawNumber = number
|
|
|
- case let string as String:
|
|
|
- _type = .string
|
|
|
- self.rawString = string
|
|
|
- case _ as NSNull:
|
|
|
- _type = .null
|
|
|
- case let array as [Any]:
|
|
|
- _type = .array
|
|
|
- self.rawArray = array
|
|
|
- case let dictionary as [String : Any]:
|
|
|
- _type = .dictionary
|
|
|
- self.rawDictionary = dictionary
|
|
|
- default:
|
|
|
- _type = .unknown
|
|
|
- _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// json type
|
|
|
- public var type: Type { get { return _type } }
|
|
|
-
|
|
|
- /// Error in JSON
|
|
|
- public var error: NSError? { get { return self._error } }
|
|
|
-
|
|
|
- /// The static null json
|
|
|
- @available(*, unavailable, renamed:"null")
|
|
|
- public static var nullJSON: JSON { get { return null } }
|
|
|
- public static var null: JSON { get { return JSON(NSNull()) } }
|
|
|
-}
|
|
|
-
|
|
|
-public enum JSONIndex:Comparable {
|
|
|
- case array(Int)
|
|
|
- case dictionary(DictionaryIndex<String, JSON>)
|
|
|
- case null
|
|
|
-}
|
|
|
-
|
|
|
-public func ==(lhs: JSONIndex, rhs: JSONIndex) -> Bool {
|
|
|
- switch (lhs, rhs) {
|
|
|
- case (.array(let left), .array(let right)):
|
|
|
- return left == right
|
|
|
- case (.dictionary(let left), .dictionary(let right)):
|
|
|
- return left == right
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-public func <(lhs: JSONIndex, rhs: JSONIndex) -> Bool {
|
|
|
- switch (lhs, rhs) {
|
|
|
- case (.array(let left), .array(let right)):
|
|
|
- return left < right
|
|
|
- case (.dictionary(let left), .dictionary(let right)):
|
|
|
- return left < right
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-extension JSON: Collection {
|
|
|
-
|
|
|
- public typealias Index = JSONIndex
|
|
|
-
|
|
|
- public var startIndex: Index{
|
|
|
- switch type {
|
|
|
- case .array:
|
|
|
- return .array(rawArray.startIndex)
|
|
|
- case .dictionary:
|
|
|
- return .dictionary(dictionaryValue.startIndex)
|
|
|
- default:
|
|
|
- return .null
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var endIndex: Index{
|
|
|
- switch type {
|
|
|
- case .array:
|
|
|
- return .array(rawArray.endIndex)
|
|
|
- case .dictionary:
|
|
|
- return .dictionary(dictionaryValue.endIndex)
|
|
|
- default:
|
|
|
- return .null
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public func index(after i: Index) -> Index {
|
|
|
- switch i {
|
|
|
- case .array(let idx):
|
|
|
- return .array(rawArray.index(after: idx))
|
|
|
- case .dictionary(let idx):
|
|
|
- return .dictionary(dictionaryValue.index(after: idx))
|
|
|
- default:
|
|
|
- return .null
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- public subscript (position: Index) -> (String, JSON) {
|
|
|
- switch position {
|
|
|
- case .array(let idx):
|
|
|
- return (String(idx), JSON(self.rawArray[idx]))
|
|
|
- case .dictionary(let idx):
|
|
|
- return dictionaryValue[idx]
|
|
|
- default:
|
|
|
- return ("", JSON.null)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Subscript
|
|
|
-
|
|
|
-/**
|
|
|
-* To mark both String and Int can be used in subscript.
|
|
|
-*/
|
|
|
-public enum JSONKey {
|
|
|
- case index(Int)
|
|
|
- case key(String)
|
|
|
-}
|
|
|
-
|
|
|
-public protocol JSONSubscriptType {
|
|
|
- var jsonKey:JSONKey { get }
|
|
|
-}
|
|
|
-
|
|
|
-extension Int: JSONSubscriptType {
|
|
|
- public var jsonKey:JSONKey {
|
|
|
- return JSONKey.index(self)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension String: JSONSubscriptType {
|
|
|
- public var jsonKey:JSONKey {
|
|
|
- return JSONKey.key(self)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- /// If `type` is `.Array`, return json whose object is `array[index]`, otherwise return null json with error.
|
|
|
- fileprivate subscript(index index: Int) -> JSON {
|
|
|
- get {
|
|
|
- if self.type != .array {
|
|
|
- var r = JSON.null
|
|
|
- r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
|
|
|
- return r
|
|
|
- } else if index >= 0 && index < self.rawArray.count {
|
|
|
- return JSON(self.rawArray[index])
|
|
|
- } else {
|
|
|
- var r = JSON.null
|
|
|
- r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
|
|
|
- return r
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- if self.type == .array {
|
|
|
- if self.rawArray.count > index && newValue.error == nil {
|
|
|
- self.rawArray[index] = newValue.object
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// If `type` is `.Dictionary`, return json whose object is `dictionary[key]` , otherwise return null json with error.
|
|
|
- fileprivate subscript(key key: String) -> JSON {
|
|
|
- get {
|
|
|
- var r = JSON.null
|
|
|
- if self.type == .dictionary {
|
|
|
- if let o = self.rawDictionary[key] {
|
|
|
- r = JSON(o)
|
|
|
- } else {
|
|
|
- r._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
|
|
|
- }
|
|
|
- } else {
|
|
|
- r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
|
|
|
- }
|
|
|
- return r
|
|
|
- }
|
|
|
- set {
|
|
|
- if self.type == .dictionary && newValue.error == nil {
|
|
|
- self.rawDictionary[key] = newValue.object
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
|
|
|
- fileprivate subscript(sub sub: JSONSubscriptType) -> JSON {
|
|
|
- get {
|
|
|
- switch sub.jsonKey {
|
|
|
- case .index(let index): return self[index: index]
|
|
|
- case .key(let key): return self[key: key]
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- switch sub.jsonKey {
|
|
|
- case .index(let index): self[index: index] = newValue
|
|
|
- case .key(let key): self[key: key] = newValue
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- Find a json in the complex data structuresby using the Int/String's array.
|
|
|
-
|
|
|
- - parameter path: The target json's path. Example:
|
|
|
-
|
|
|
- let json = JSON[data]
|
|
|
- let path = [9,"list","person","name"]
|
|
|
- let name = json[path]
|
|
|
-
|
|
|
- The same as: let name = json[9]["list"]["person"]["name"]
|
|
|
-
|
|
|
- - returns: Return a json found by the path or a null json with error
|
|
|
- */
|
|
|
- public subscript(path: [JSONSubscriptType]) -> JSON {
|
|
|
- get {
|
|
|
- return path.reduce(self) { $0[sub: $1] }
|
|
|
- }
|
|
|
- set {
|
|
|
- switch path.count {
|
|
|
- case 0:
|
|
|
- return
|
|
|
- case 1:
|
|
|
- self[sub:path[0]].object = newValue.object
|
|
|
- default:
|
|
|
- var aPath = path; aPath.remove(at: 0)
|
|
|
- var nextJSON = self[sub: path[0]]
|
|
|
- nextJSON[aPath] = newValue
|
|
|
- self[sub: path[0]] = nextJSON
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- Find a json in the complex data structures by using the Int/String's array.
|
|
|
-
|
|
|
- - parameter path: The target json's path. Example:
|
|
|
-
|
|
|
- let name = json[9,"list","person","name"]
|
|
|
-
|
|
|
- The same as: let name = json[9]["list"]["person"]["name"]
|
|
|
-
|
|
|
- - returns: Return a json found by the path or a null json with error
|
|
|
- */
|
|
|
- public subscript(path: JSONSubscriptType...) -> JSON {
|
|
|
- get {
|
|
|
- return self[path]
|
|
|
- }
|
|
|
- set {
|
|
|
- self[path] = newValue
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - LiteralConvertible
|
|
|
-
|
|
|
-extension JSON: Swift.StringLiteralConvertible {
|
|
|
-
|
|
|
- public init(stringLiteral value: StringLiteralType) {
|
|
|
- self.init(value)
|
|
|
- }
|
|
|
-
|
|
|
- public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
|
|
|
- self.init(value)
|
|
|
- }
|
|
|
-
|
|
|
- public init(unicodeScalarLiteral value: StringLiteralType) {
|
|
|
- self.init(value)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension JSON: Swift.IntegerLiteralConvertible {
|
|
|
-
|
|
|
- public init(integerLiteral value: IntegerLiteralType) {
|
|
|
- self.init(value)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension JSON: Swift.BooleanLiteralConvertible {
|
|
|
-
|
|
|
- public init(booleanLiteral value: BooleanLiteralType) {
|
|
|
- self.init(value)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension JSON: Swift.FloatLiteralConvertible {
|
|
|
-
|
|
|
- public init(floatLiteral value: FloatLiteralType) {
|
|
|
- self.init(value)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension JSON: Swift.DictionaryLiteralConvertible {
|
|
|
-
|
|
|
- public init(dictionaryLiteral elements: (String, Any)...) {
|
|
|
- self.init(elements.reduce([String : Any](minimumCapacity: elements.count)){(dictionary: [String : Any], element:(String, Any)) -> [String : Any] in
|
|
|
- var d = dictionary
|
|
|
- d[element.0] = element.1
|
|
|
- return d
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension JSON: Swift.ArrayLiteralConvertible {
|
|
|
-
|
|
|
- public init(arrayLiteral elements: Any...) {
|
|
|
- self.init(elements)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-extension JSON: Swift.NilLiteralConvertible {
|
|
|
-
|
|
|
- public init(nilLiteral: ()) {
|
|
|
- self.init(NSNull())
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Raw
|
|
|
-
|
|
|
-extension JSON: Swift.RawRepresentable {
|
|
|
-
|
|
|
- public init?(rawValue: Any) {
|
|
|
- if JSON(rawValue).type == .unknown {
|
|
|
- return nil
|
|
|
- } else {
|
|
|
- self.init(rawValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var rawValue: Any {
|
|
|
- return self.object
|
|
|
- }
|
|
|
-
|
|
|
- public func rawData(options opt: JSONSerialization.WritingOptions = JSONSerialization.WritingOptions(rawValue: 0)) throws -> Data {
|
|
|
- guard JSONSerialization.isValidJSONObject(self.object) else {
|
|
|
- throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "JSON is invalid"])
|
|
|
- }
|
|
|
-
|
|
|
- return try JSONSerialization.data(withJSONObject: self.object, options: opt)
|
|
|
- }
|
|
|
-
|
|
|
- public func rawString(_ encoding: String.Encoding = String.Encoding.utf8, options opt: JSONSerialization.WritingOptions = .prettyPrinted) -> String? {
|
|
|
- switch self.type {
|
|
|
- case .array, .dictionary:
|
|
|
- do {
|
|
|
- let data = try self.rawData(options: opt)
|
|
|
- return String(data: data, encoding: encoding)
|
|
|
- } catch _ {
|
|
|
- return nil
|
|
|
- }
|
|
|
- case .string:
|
|
|
- return self.rawString
|
|
|
- case .number:
|
|
|
- return self.rawNumber.stringValue
|
|
|
- case .bool:
|
|
|
- return self.rawNumber.boolValue.description
|
|
|
- case .null:
|
|
|
- return "null"
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Printable, DebugPrintable
|
|
|
-
|
|
|
-extension JSON: Swift.CustomStringConvertible, Swift.CustomDebugStringConvertible {
|
|
|
-
|
|
|
- public var description: String {
|
|
|
- if let string = self.rawString(options:.prettyPrinted) {
|
|
|
- return string
|
|
|
- } else {
|
|
|
- return "unknown"
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var debugDescription: String {
|
|
|
- return description
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Array
|
|
|
-
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- //Optional [JSON]
|
|
|
- public var array: [JSON]? {
|
|
|
- get {
|
|
|
- if self.type == .array {
|
|
|
- return self.rawArray.map{ JSON($0) }
|
|
|
- } else {
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //Non-optional [JSON]
|
|
|
- public var arrayValue: [JSON] {
|
|
|
- get {
|
|
|
- return self.array ?? []
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //Optional [Any]
|
|
|
- public var arrayObject: [Any]? {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .array:
|
|
|
- return self.rawArray
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- if let array = newValue {
|
|
|
- self.object = array
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Dictionary
|
|
|
-
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- //Optional [String : JSON]
|
|
|
- public var dictionary: [String : JSON]? {
|
|
|
- if self.type == .dictionary {
|
|
|
-
|
|
|
- return self.rawDictionary.reduce([String : JSON]()) { (dictionary: [String : JSON], element: (String, Any)) -> [String : JSON] in
|
|
|
- var d = dictionary
|
|
|
- d[element.0] = JSON(element.1)
|
|
|
- return d
|
|
|
- }
|
|
|
- } else {
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //Non-optional [String : JSON]
|
|
|
- public var dictionaryValue: [String : JSON] {
|
|
|
- return self.dictionary ?? [:]
|
|
|
- }
|
|
|
-
|
|
|
- //Optional [String : Any]
|
|
|
- public var dictionaryObject: [String : Any]? {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .dictionary:
|
|
|
- return self.rawDictionary
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- if let v = newValue {
|
|
|
- self.object = v
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Bool
|
|
|
-
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- //Optional bool
|
|
|
- public var bool: Bool? {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .bool:
|
|
|
- return self.rawNumber.boolValue
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //Non-optional bool
|
|
|
- public var boolValue: Bool {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .bool, .number, .string:
|
|
|
- return (self.object as AnyObject).boolValue
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - String
|
|
|
-
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- //Optional string
|
|
|
- public var string: String? {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .string:
|
|
|
- return self.object as? String
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSString(string:newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //Non-optional string
|
|
|
- public var stringValue: String {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .string:
|
|
|
- return self.object as? String ?? ""
|
|
|
- case .number:
|
|
|
- return (self.object as AnyObject).stringValue
|
|
|
- case .bool:
|
|
|
- return (self.object as? Bool).map { String($0) } ?? ""
|
|
|
- default:
|
|
|
- return ""
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSString(string:newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Number
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- //Optional number
|
|
|
- public var number: NSNumber? {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .number, .bool:
|
|
|
- return self.rawNumber
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = newValue ?? NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //Non-optional number
|
|
|
- public var numberValue: NSNumber {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .string:
|
|
|
- let decimal = NSDecimalNumber(string: self.object as? String)
|
|
|
- if decimal == NSDecimalNumber.notANumber { // indicates parse error
|
|
|
- return NSDecimalNumber.zero
|
|
|
- }
|
|
|
- return decimal
|
|
|
- case .number, .bool:
|
|
|
- return self.object as? NSNumber ?? NSNumber(value: 0)
|
|
|
- default:
|
|
|
- return NSNumber(value: 0.0)
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = newValue
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//MARK: - Null
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- public var null: NSNull? {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .null:
|
|
|
- return self.rawNull
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- public func exists() -> Bool{
|
|
|
- if let errorValue = error, errorValue.code == ErrorNotExist{
|
|
|
- return false
|
|
|
- }
|
|
|
- return true
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//MARK: - URL
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- //Optional URL
|
|
|
- public var URL: Foundation.URL? {
|
|
|
- get {
|
|
|
- switch self.type {
|
|
|
- case .string:
|
|
|
- if let encodedString_ = self.rawString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) {
|
|
|
- return Foundation.URL(string: encodedString_)
|
|
|
- } else {
|
|
|
- return nil
|
|
|
- }
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = newValue?.absoluteString ?? NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
|
|
|
-
|
|
|
-extension JSON {
|
|
|
-
|
|
|
- public var double: Double? {
|
|
|
- get {
|
|
|
- return self.number?.doubleValue
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var doubleValue: Double {
|
|
|
- get {
|
|
|
- return self.numberValue.doubleValue
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var float: Float? {
|
|
|
- get {
|
|
|
- return self.number?.floatValue
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var floatValue: Float {
|
|
|
- get {
|
|
|
- return self.numberValue.floatValue
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int: Int? {
|
|
|
- get {
|
|
|
- return self.number?.intValue
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var intValue: Int {
|
|
|
- get {
|
|
|
- return self.numberValue.intValue
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt: UInt? {
|
|
|
- get {
|
|
|
- return self.number?.uintValue
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uIntValue: UInt {
|
|
|
- get {
|
|
|
- return self.numberValue.uintValue
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int8: Int8? {
|
|
|
- get {
|
|
|
- return self.number?.int8Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int8Value: Int8 {
|
|
|
- get {
|
|
|
- return self.numberValue.int8Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt8: UInt8? {
|
|
|
- get {
|
|
|
- return self.number?.uint8Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt8Value: UInt8 {
|
|
|
- get {
|
|
|
- return self.numberValue.uint8Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int16: Int16? {
|
|
|
- get {
|
|
|
- return self.number?.int16Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int16Value: Int16 {
|
|
|
- get {
|
|
|
- return self.numberValue.int16Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt16: UInt16? {
|
|
|
- get {
|
|
|
- return self.number?.uint16Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt16Value: UInt16 {
|
|
|
- get {
|
|
|
- return self.numberValue.uint16Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int32: Int32? {
|
|
|
- get {
|
|
|
- return self.number?.int32Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int32Value: Int32 {
|
|
|
- get {
|
|
|
- return self.numberValue.int32Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt32: UInt32? {
|
|
|
- get {
|
|
|
- return self.number?.uint32Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt32Value: UInt32 {
|
|
|
- get {
|
|
|
- return self.numberValue.uint32Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int64: Int64? {
|
|
|
- get {
|
|
|
- return self.number?.int64Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var int64Value: Int64 {
|
|
|
- get {
|
|
|
- return self.numberValue.int64Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt64: UInt64? {
|
|
|
- get {
|
|
|
- return self.number?.uint64Value
|
|
|
- }
|
|
|
- set {
|
|
|
- if let newValue = newValue {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- } else {
|
|
|
- self.object = NSNull()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public var uInt64Value: UInt64 {
|
|
|
- get {
|
|
|
- return self.numberValue.uint64Value
|
|
|
- }
|
|
|
- set {
|
|
|
- self.object = NSNumber(value: newValue)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//MARK: - Comparable
|
|
|
-extension JSON : Swift.Comparable {}
|
|
|
-
|
|
|
-public func ==(lhs: JSON, rhs: JSON) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.type, rhs.type) {
|
|
|
- case (.number, .number):
|
|
|
- return lhs.rawNumber == rhs.rawNumber
|
|
|
- case (.string, .string):
|
|
|
- return lhs.rawString == rhs.rawString
|
|
|
- case (.bool, .bool):
|
|
|
- return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue
|
|
|
- case (.array, .array):
|
|
|
- return lhs.rawArray as NSArray == rhs.rawArray as NSArray
|
|
|
- case (.dictionary, .dictionary):
|
|
|
- return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
|
|
|
- case (.null, .null):
|
|
|
- return true
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-public func <=(lhs: JSON, rhs: JSON) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.type, rhs.type) {
|
|
|
- case (.number, .number):
|
|
|
- return lhs.rawNumber <= rhs.rawNumber
|
|
|
- case (.string, .string):
|
|
|
- return lhs.rawString <= rhs.rawString
|
|
|
- case (.bool, .bool):
|
|
|
- return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue
|
|
|
- case (.array, .array):
|
|
|
- return lhs.rawArray as NSArray == rhs.rawArray as NSArray
|
|
|
- case (.dictionary, .dictionary):
|
|
|
- return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
|
|
|
- case (.null, .null):
|
|
|
- return true
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-public func >=(lhs: JSON, rhs: JSON) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.type, rhs.type) {
|
|
|
- case (.number, .number):
|
|
|
- return lhs.rawNumber >= rhs.rawNumber
|
|
|
- case (.string, .string):
|
|
|
- return lhs.rawString >= rhs.rawString
|
|
|
- case (.bool, .bool):
|
|
|
- return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue
|
|
|
- case (.array, .array):
|
|
|
- return lhs.rawArray as NSArray == rhs.rawArray as NSArray
|
|
|
- case (.dictionary, .dictionary):
|
|
|
- return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
|
|
|
- case (.null, .null):
|
|
|
- return true
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-public func >(lhs: JSON, rhs: JSON) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.type, rhs.type) {
|
|
|
- case (.number, .number):
|
|
|
- return lhs.rawNumber > rhs.rawNumber
|
|
|
- case (.string, .string):
|
|
|
- return lhs.rawString > rhs.rawString
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-public func <(lhs: JSON, rhs: JSON) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.type, rhs.type) {
|
|
|
- case (.number, .number):
|
|
|
- return lhs.rawNumber < rhs.rawNumber
|
|
|
- case (.string, .string):
|
|
|
- return lhs.rawString < rhs.rawString
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-fileprivate let trueNumber = NSNumber(value: true)
|
|
|
-fileprivate let falseNumber = NSNumber(value: false)
|
|
|
-fileprivate let trueObjCType = String(cString: trueNumber.objCType)
|
|
|
-fileprivate let falseObjCType = String(cString: falseNumber.objCType)
|
|
|
-
|
|
|
-
|
|
|
-//A C++ bool or a C99 _Bool
|
|
|
-//Do Not Know Why self.objCType is "B", maybe a bug.
|
|
|
-fileprivate let cppBoolType = "B"
|
|
|
-
|
|
|
-// MARK: - NSNumber: Comparable
|
|
|
-
|
|
|
-extension NSNumber {
|
|
|
- var isBool:Bool {
|
|
|
- get {
|
|
|
-
|
|
|
- let objCType = String(cString: self.objCType)
|
|
|
-
|
|
|
- if (self.compare(trueNumber) == ComparisonResult.orderedSame && (objCType == trueObjCType || objCType == cppBoolType))
|
|
|
- || (self.compare(falseNumber) == ComparisonResult.orderedSame && (objCType == falseObjCType || objCType == cppBoolType)){
|
|
|
- return true
|
|
|
- } else {
|
|
|
- return false
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
|
|
|
- switch (lhs.isBool, rhs.isBool) {
|
|
|
- case (false, true):
|
|
|
- return false
|
|
|
- case (true, false):
|
|
|
- return false
|
|
|
- default:
|
|
|
- return lhs.compare(rhs) == ComparisonResult.orderedSame
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
|
|
|
- return !(lhs == rhs)
|
|
|
-}
|
|
|
-
|
|
|
-func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.isBool, rhs.isBool) {
|
|
|
- case (false, true):
|
|
|
- return false
|
|
|
- case (true, false):
|
|
|
- return false
|
|
|
- default:
|
|
|
- return lhs.compare(rhs) == ComparisonResult.orderedAscending
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.isBool, rhs.isBool) {
|
|
|
- case (false, true):
|
|
|
- return false
|
|
|
- case (true, false):
|
|
|
- return false
|
|
|
- default:
|
|
|
- return lhs.compare(rhs) == ComparisonResult.orderedDescending
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.isBool, rhs.isBool) {
|
|
|
- case (false, true):
|
|
|
- return false
|
|
|
- case (true, false):
|
|
|
- return false
|
|
|
- default:
|
|
|
- return lhs.compare(rhs) != ComparisonResult.orderedDescending
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
|
|
|
-
|
|
|
- switch (lhs.isBool, rhs.isBool) {
|
|
|
- case (false, true):
|
|
|
- return false
|
|
|
- case (true, false):
|
|
|
- return false
|
|
|
- default:
|
|
|
- return lhs.compare(rhs) != ComparisonResult.orderedAscending
|
|
|
- }
|
|
|
-}
|