Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2016-07-12

VJson release v0.9.8 | A Single Class JSON Hierarchy in Swift

I have released a new version of VJson, a JSON hierarchy that can be used to create and parse JSON code.

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}

Note that the subscript accessor actually creates the JSON code parts that are needed to fulfil the whole request. Thus it is possible to create a fully formed JSON hierarchy in two lines:

let json = VJson()
json["Books"][2]["available"] &= true

Creates the JSON code {"Books":[null,null,{"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 { ... }

Or in a guard statement:

guard let title = (json|"Books"|23|"title")?.stringValue else { ... }

Iteration is also possible:

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

And lastly, how to chain a complex type into generating a representative JSON code:

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.

Happy coding...

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