How to deserialize json with nested Dictionaries? - json

For some endpoints SimpleGeo.com returns something like this:
{
"geometry":{
"type":"Point",
"coordinates":[
-122.421583,
37.795027
]
},
"type":"Feature",
"id":SG_5JkVsYK82eLj26eomFrI7S_37.795027_-122.421583#1291796505,
"properties":{
"province":"CA",
"city":"San Francisco",
"name":"Bell Tower",
"tags":[],
"country":"US",
"phone":"+1 415 567 9596",
"href": http://api.simplegeo.com/1.0/features/SG_5JkVsYK82eLj26eomFrI7S_37.795027_-122.421583#1291796505.json,
"address":"1900 Polk St",
"owner":"simplegeo",
"postcode":"94109",
"classifiers":[
{
"category":"Restaurant",
"type":"Food & Drink",
"subcategory":""
}
]
}
}
(see http://simplegeo.com/docs/api-endpoints/simplegeo-features#get-detailed-information).
Now I have a small problem deserializing the 'properties' part. If I use e.g. a type of Dictionary it converts it to a nice dictionary, but the 'classifiers' value is just one {} string.
Is there any way to tell json.net to deserialize sub-arrays into yet another Dictionary etc etc? Basically there's an amount of plain key/values in that return, but I do know that there might be more than just that 'classifiers' sub-array (see the 'tags'), and maybe the depth goes even further in the values...
So basically what I was wondering is, how do I properly deserialize the properties part? Any suggestions? I don't mind writing my own JsonConverter, but maybe there is already a way that works without it.

I've found a solution for a similar question over here:
Json.NET: Deserializing nested dictionaries.
It uses a custom JsonConverter and I don't see a way to do without it.

Related

JSON schema conditional check in JSON object within array

Here is the desired schema and json for illustration purpose. Please see the link below.
JSON Schema and JSON
{
"id": "123" ,
"ts": "1234567890",
"complex_rules":
[
{
"type":"admin",
"rule":{
"rights":"all",
"remarks": "some admin remarks"
}
},
{
"type":"guest",
"rights": "limited"
},
{
"type":"anonymous",
"rights": "blocked"
}
]
}
The 'complex_rules' is an array of json object:
With type either be a : "admin", "guest", "anonymous" and the 'type' attribute is MANDATORY.
Each object in array can have its own structure, but the type can be either of: "admin", "guest", "anonymous" only. No other type attribute is acceptable.
The conditions to evaluate:
The type of object in the array cannot re-occur in the array. (I know this seems to be not possible, so we can ignore this)
If attribute "rights" in the {type=admin object} with any value, then we cannot have "rights": "limited" or any value in {type=guest object}. The JSON Schema validation must complain about this.
Another twist, either object {type":"guest"}or {type":"anonymous"} can exist. Both types cannot coexist along with other types.
----Update
The above link is the solution this question.
In regards to 1 and 2:
You need to use a combination of if, then, and not keywords to construct the logic you require with the correct level of applicability.
In regards to 3:
The type of object in the array cannot re-occur in the array. (I know
this seems to be not possible, so we can ignore this)
Right, that's correct, it's not possible as of draft-7 JSON Schema.

JSON data, properties are sometimes arrays sometimes objects

I'm reading a JSON response from a third party and I'm finding that some of the properties return in the notation for a single object when there is only one object to be returned and when there is multiple objects for the property the value is returned as an array of objects.
Example of a single object in the response
{
"data": {
"property1":"value",
"property2":"value",
"property3":"value"
}
}
Example of an array of objects in the response
{
"data": [
{
"property1":"value",
"property2":"value",
"property3":"value"
},
{
"property1":"value",
"property2":"value",
"property3":"value"
},
{
"property1":"value",
"property2":"value",
"property3":"value"
},
{
"property1":"value",
"property2":"value",
"property3":"value"
}
]
}
Why would the two different response formats be acceptable from the same endpoint?
This question bothered me as well whenever I saw it happening. I never really liked having to check the value in order to know how to access it.
One could argue that doing this saves some space in the payload. You save two bytes omitting the [] when there's only a single value. But it's weak IMHO and manipulating the data is harder as we already know.
But looking at it in a different way, this seems to make some sense: it's optimizing for the more common result, a single value. I've seen my fair share of data formats where the structure was very strict. For example, a recursive dictionary-like structure where any property that would contain an object, must be an array of that object. So in a deeply nested object, accessing a value may look like this:
root.data[0].aparent[0].thechild[0].myvalue
vs:
root.data.aparent.thechild.myvalue
If there were actually multiple values, then using an array would be appropriate.
I don't necessarily buy this since you still have to do a check, you'd have to do some tests before consuming the data (like if a response didn't came back). This type of response might make more sense in languages that have some form of pattern matching.

TJSONUnMarshal: how to track what is actually unmarshalled

Is there another way to track what is unmarshalled than write own reverter for each field?
I'm updating my local data based on json message and my problem is (simplified):
I'm expecting json like
{ "items": [ { "id":1, "name":"foobar", "price":"12.34" } ] }
which is then unmarshaled to class TItems by
UnMarshaller.TryCreateObject( TItems, TJsonObject( OneJsonElement ), TargetItem )
My problem is that I can't make difference between
{ "items": [ { "id":1, "name":"", "price":"12.34" } ] }
and
{ "items": [ { "id":1, "price":"12.34" } ] }
In both cases name is blank and i'd like to update only those fields that are passed on json message. Of course I could create a reverted for each field, but there are plenty of fields and messages so it's quite huge.
I tried to look REST.Jsonreflect.pas source, but couldn't make sense.
I'm using delphi 10.
In Rest.Json unit there is a TJson class defined that offers several convenience methods like converting objects to JSON and vice versa. Specifically, it has a class function JsonToObject where you can specify options like for example ignore empty strings or ignore empty arrays. I think the TJson class can serve you. For unmarshalling complex business objects you have to write custom converters though.
Actually, my problem was finally simple to solve.
Instead of using TJSONUnMarshal.tryCreateObject I use now TJSONUnMarshal.CreateObject. First one has object parameters declared with out modifier, but CreateObject has Object parameter var modifier, so I was able to
create object, initalize it from database and pass it to CreateObject which only modifies fields in json message.

JSON Reference to non-object value

We are currently investigating JSON as a potential API data transfer language for our system and a question about using JSON Reference came up.
Consider the following example:
{
"invoice-address" : { "street": "John Street", "zip": "12345", "city": "Someville" },
"shipping-address": { "$ref": "#/invoice-address" }
}
According to our research, this is a valid usage of JSON Reference. We replace the instance of an object with another object containing the reference pointing to a different object using a JSON Pointer fragment.
Now, a JSON Reference always consists of a key-value pair and thus has to be enclosed in an object. This would mean that in order to reference a non-object data type (e.g. the zip and city strings in the example above) you would have to do the following:
{
"invoice-address" : { "street": "John Street", "zip": "12345", "city": "Someville" },
"shipping-address": { "street": "Doe Street", "zip": { "$ref": "#/invoice-address/zip" }, "city": { "$ref": "#/invoice-address/city" } }
}
Even though the JSON Pointers now correctly point to string values, we had to change the data type of zip and city from string to object, which make them fail validation against our JSON Schema, because it declares them as strings.
However, the JSON Reference draft states:
Implementations MAY choose to replace the reference with the referenced value.
Does that mean that we are allowed to "preprocess" the file and replace the JSON Reference object with the resolved string value before validating against the JSON Schema? Or are references limited to object types only?
Thanks to anyone who can shed some light onto this.
I wouldn't expect most validators to resolve JSON References before validation. You could either:
resolve JSON References before validation
adapt the JSON Schemas to allow for JSON Reference objects in certain places
Personally, I think the first option is much neater.
You could end up with circular references I suppose - I don't know which validator/language you're using, but tv4 can definitely handle it.

Point of JSON-RPC vs simpler JSON

this is a JSON-RPC object I am implementing
{
"method":"create",
"params": [
{
"nid": "69",
"body":
{
"und":
[
{
"value":
"blah"
}
]
}
}
]
}
here is how I would do it with "normal" JSON
{
"method":"create",
"id":"69",
"value":"blah"
}
since JSON is a parsed as a map or dictionary, this should be adequate regardless of the presence of nested JSONArrays and JSON Objects in those arrays, explain why JSON-RPC is better or desired by anything at all
thanks!
Your JSON-RPC is invalid; id has to be at the top level, as it is in your "normal" JSON
After correcting for the above, your JSON-RPC is still needlessly complex; params could just be [{"value":"blah"}]. Which would make your "normal" JSON very slightly less complex, but harder to parse (since you couldn't rely on "params" no matter what)
Your "normal" JSON would not allow for unnamed parameters (ones identified solely by position). Thus, the minimal added complexity buys you something which you might not need in your application, but others might