Yet another JSON parser? Yes.
For some reasons I needed to own the sources that could be used to create JSON code and to parse JSON code. A simple way to achieve this is to write your own...
It also has the advantage that I get to decide how the interface looks. And that is quite important to me. Usage should be easy. And I believe I have achieved just that. I have not studied other implementations, and I am sure there are (many?) similar solutions "out there".
So how easy is it?
For starters, it consists of a single class: VJson. Of course a VJson object can contain other VJson objects. And then, wel, there is parsing:
let json = try VJson.parse(sourceData)
Where source-data can be a String, a (file)URL, NSMutableData or a buffer. Sometimes with additional parameters. There is of course also a non-throwing alternative (with an extra parameter).
Then there is creation of JSON code:
let json = VJson()
print(json.description) // Prints "{}", i.e an empty JSON code.
Adding values to the JSON hierarchy:
json["Test"] &= true // Code = {"Test":true}
json["Another"] &= 13 // Code = {"Test":true,"Another":13}
let json = VJson()
json["Books"][2]["available"] &= true
Notice how two "null" items have been automatically inserted to fulfil the array subscript accessor.
Having the subscript accessors create the items as necessary makes them impossible to use for testing of items if you do not want to change the JSON hierarchy for non-existing items. For that purpose the UNIX pipe symbol is used:
To test if book number 23 exists:
if json|"Books"|23 != nil { ... }
guard let title = (json|"Books"|23|"title")?.stringValue else { ... }
for item in json {...}
This will iterate the children of OBJECT and ARRAY JSON items.
The "name" (i.e. the tag in a JSON OBJECT used to identify a child item) is available as the "nameValue" of an item. Thus when iterating an OBJECT the name can be read by:
for item in json {
let name = item.nameValue
}
Items contained in an array may have a name as well, however these names will not be part of the generated code.
VJson uses 'null' as a substitute for 'nil'. Assigning an optional to an item will generate the value 'null' if that optional is nil. Example:
let json = VJson()
var title: String?
json["Title"] &= title // Code = {"Title":null}
It is often possible to convert values. I.e. you could read a number as a string, or certain strings as booleans. For those situations VJson offers the "as...." accessors.
let json = try VJson.parse("{\"label\":true}")
let labelIsTrue = (json|"label")?.asBool
class Inner {
var a: Int?
var json: VJson {
let j = VJson()
j["A"] &= a
return j
}
}
class Outer {
var b = Inner()
var c: String?
var json: VJson {
let j = VJson()
j["C"] &= c
j.add(b.json, forName: "B")
return j
}
}
let k = Outer()
print(k.json)
This is the way I do it, but other ways are possible of course. In defence of the present method: It keeps information where it should be (I.e. the name of the Inner item is part of the Outer item) and creates a clear distinction between local properties that do not have an internal structure and properties that have a bested structure.
You can download VJson from Github.
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH
We don't get the world we wish for... we get the world we pay for.
No comments:
Post a Comment