How can I access high level JSON object in Objective-c? Here's the JSON
{
user: "user",
id: 39,
image: "img.png",
caption: "",
lat: "37",
lng: "-122",
created_at: 1356910240
}
... and I need to do something like this [JSON valueFor???:????]
I can add object "identifier" and access it like [JSON valueForKeyPath:#"identifier"] but wondering if there is another way?
identifier: {
user: "user",
id: 39,
image: "img.png",
caption: "",
lat: "37",
lng: "-122",
created_at: 1356910240
}
Thanks!
Typically, a JSON parser will return a dictionary/hash/associative array, whatever the language being used uses for key/value pairs.
In ObjectiveC, that would be NSDictionary. So your parser should be doing this:
NSDictionary *data = [SomeJSONParser decodeJson:jsonString];
Now to get "user" from that we would do:
[data objectForKey:#"user"];
But you want the root node? Well you already have it. The root node is the dictionary your parser spits out. There is no magic method to call, the root node is simply the result of the parser.
If your "custom parser" works differently, I would suggest you change it. Making this do what you want is entirely dependent on the API of your parser and what types of objects it returns, both things you left incredibly vague in your question.
Related
If I define a moddle file with bpmn-js like this
{
name: "thisArgument",
superClass: [
"Element"
],
properties: []
},
{
name: "myData",
superClass: [
"Element"
],
properties: [
{
name: "argument",
type: "thisArgument"
}
]
},
Then the resulting XML (when I call saveXML) will have an element called thisArgument, despite the fact that the name is "argument". First, is that a bug? If not, how do I control the output so that the XML contains argument rather than thisArgument? I've searched the docs and examples but can't find how to do this.
The only workaround I found was to make it type: "argument" and then define argument with a superClass of thisArgument and no extra properties (essentially making an alias). However, that only works if all instances of argument are identical. Eg. if the XML needed to be
<A><argument/></A>
<B><argument/></B>
where the argument in A has a different shape than the argument in B, then there would be a conflict since I can't define argument twice.
I can sort of answer my own question. I found this serialize option and experimented, and it mostly does what I want, but sometimes it adds an unwanted xsi:type="originalType" attribute and sometimes it doesn't. Maybe it depends on isBody but I'm not sure. If anyone knows the details of how it works, please reply.
properties: [
{
name: "argument",
type: "thisArgument",
xml: {
serialize: "xsi:type"
},
}
]
The closest thing I found to documentation on it is https://forum.bpmn.io/t/bpmn-json-documentation/1304 which describes it as "additional meta-data impecting XML serialization of a type", so I'd appreciate any extra details anyone can supply.
Update:
The docs don't mention this, but it turns out that serialize: "property" is exactly what I need. This does the same as serialize: "xsi:type" but doesn't add the xsi:type attribute.
xml: {
serialize: "property"
},
I found this by hunting the code in one of the related packages, moddle-xml.
In write.js, there's code that looks for the xsi:type or property entry:
// allow serialization via type
// rather than element name
var asType = serializeAsType(p),
asProperty = serializeAsProperty(p);
In the same file, I found some code that appears to explain why the xsi:type didn't always show up, too:
// only serialize xsi:type if necessary
if (descriptor.name === this.propertyDescriptor.type) {
return attributes;
}
i am parsing json and what i get set of dictionary but after parsing it will automatically change it order. i just need same order as same i am getting from json parsing.
NOTE: i want to make one functionality which depends on dictionary order, i don't want to make it manually. so it will not need to make it every-time to do.it will help to change dynamically in future
Example:
From Json:
Section:
{
category:{},
location:{},
vehicle_type:{},
mode_type:{}
}
after convert into NSDicationary:
Section:
{
vehicle_type:{}
category:{},
location:{},
mode_type:{}
}
Thanks
Order of key:value doesn't matter for JSON, as you can directly access value with the help of key string. An dictionary does not support indexing of elements, so you can't.
Dictionaries are not ordered collections. On other hand, arrays are.
Note, if you don't have access over the json format, you got no guarantees about the order of elements, if you don't have hardcoded logic in your app.
Having said that, let's take a deeper look into your case. It happens that you have one main object in your json that is Section. What is more, you have 4 ordered properties of this object that are of specific kind of their own: 0: category; 1: location; 2: vehicle_type; 3: mode_type. So here comes the good part: just change your json to look something like this:
Section:
[
{
title: "category",
value: {}
},
{
title: "location",
value: {}
},
{
title: "vehicle_type",
value: {}
},
{
title: "mode_type",
value: {}
}
]
Having this json, you just go through the Section ordered elements, check the title of the element, and create the corresponding Object. This way you can achieve what you are after.
I have this code Json format:
{
"weather": [{
"description": "clear sky",
"icon": "01n"
}],
"base": "stations",
"main": {
"temp": 285.514
},
"clouds": {
"all": 0
},
"dt": 1485792967,
"id": 1907296
}
And I want to retrive icon string (01n)
And use this code:
#property(nonatomic,strong) NSString *cityImageName;
self.cityImageName = [[dataJson valueForKey:#"weather"] valueForKey:#"icon"];
And later when I check the variable print:
<__NSSingleObjectArrayI 0x604000009890>(
01n
)
Finally how can I get the string directly? not like a __NSSingleObjectArrayI
You got caught in the Key-Value Coding Trap.
valueForKey has a special behavior. Applied to an array it returns always an array of all values for the given key.
Never use valueForKey unless you intend to use KVC. The recommended syntax is objectForKey or – preferable – key subscription and in case of the array index subscription.
In this case you want to get the value for key icon of the first item in the array for key weather.
self.cityImageName = dataJson[#"weather"][0][#"icon"];
However I would add a check if the array is not empty to avoid an out-of-range exception
NSArray *weather = dataJson[#"weather"];
if (weather && weather.count > 0) {
self.cityImageName = weather[0][#"icon"];
}
__NSSingleObjectArrayI is one of the implementations of the NSArray class cluster. It's not really important to this question other than knowing that it's an array.
The reason you're getting an array (of one element) instead of a string is because the JSON you're working with contains an array with one dictionary inside of it:
"weather": [{
"description": "clear sky",
"icon": "01n"
}],
Note: the square brackets surrounding the curly brackets.
So, when you call [dataJson valueForKey:#"weather"] you get back the object that represent this part of the JSON:
[ { "description": "clear sky", "icon": "01n" } ]
Which is in this case has been decoded as an NSArray containing one NSDictionary with two keys.
When you then call valueForKey: on that array it
Returns an array containing the results of invoking valueForKey: using key on each of the array's objects.
In other words, because [dataJson valueForKey:#"weather"] is an array of one dictionary, [[dataJson valueForKey:#"weather"] valueForKey:#"icon"] is an array of only the value for the "icon" key in that dictionary.
If the JSON you're working with always has this format, then you can get the firstObject from the array to get a hold of the first string (or nil if the array was empty).
Hi i am trying to get the subject name value out of the following JSON file (dataArray), which I have already run through NSJSONSERIALISATION:
-0: {
id: "55edc05848177ec741daf79e"
firstName: "Brad"
rating: 4.2
lessons: 5
text: "Lessons, they're yours take it"
-subjects: [4]
-0: {
name: "Indonesian"
pricePerHour: "500000"
}
-1: {
name: "Diving"
pricePerHour: "700000"
}
But am not able to access if using the indexPath and dot notation I have used for other elements. I'm understanding it must because I have to access an NSDictionary element within two arrays, however haven't been able to find the correct code to do this (though have looked a lot on here, most examples are for much simpler cases).
Here is the code I have been trying, but as I mentioned I now see that this code doesn't cover the array within array of the JSON. How should I modify this to get the value:
// Load and display subjects
UILabel *subjectLabel = (UILabel *)[cell viewWithTag:103];
NSString * subject1String = [dataArray[indexPath.row] valueForKeyPath: #"subjects.0.name"];
subjectLabel.text = [NSString stringWithFormat:#"%#", subject1String];
I think this is not valid Json. Print response as you are getting from the server end. And for getting name : you need to add loop.
I see that the restkit document is quite nice and has variety of examples on object modelling. There is also an example of nested mapping but I find my scenario little bit different than this. RestKit documentation provides the example mapping of the nested attribute with the following json format.
Sample JSON structure from the RestKit Documentation :
{
"blake": {
"email": "blake#restkit.org",
"favorite_animal": "Monkey"
},
"sarah": {
"email": "sarah#restkit.org",
"favorite_animal": "Cat"
}
}
Suppose that my json is a bit different as this;
My JSON structure :
{
"id" : 1,
"author" : "RestKit",
"blake": {
"email": "blake#restkit.org",
"favorite_animal": "Monkey"
},
"sarah": {
"email": "sarah#restkit.org",
"favorite_animal": "Cat"
}
}
I created two different managedobject model with the following attributes and to many relations.
Two different entities for my structure Product and creator to map the above JSON object.
Product Creator
identifier <------------------- >> name
author email
favouriteAnimal
Now, my mapping would look like this for Product model would be;
This is how I map the Product entity,
[mapping mapKeyPath:"id" toAttribute:"identifier"];
[mapping mapKeyPath:"author" toAttribute: "author"];
But note here, mapping the nested dictionary attribute does not work for me.
// [mapping mapKeyOfNestedDictionaryToAttribute:#"creators"];
Now, in the authors class.
I could not figure out the usual way to map the above JSON structure.
If you have control over the web service, I would strongly recommend reorganizing your response data like this:
{
product:
{
id: 1,
author: 'RestKit',
creators: [
{
id: 1,
name: 'Blake',
email: '...',
favorite_animal: 'Monkey'
},
{
id: 2,
name: 'Sarah',
email: '...',
favorite_animal: 'Cat'
}
]
}
}
Following this structure, you'd be able to use RestKit's nested mapping features, and the relationship would be correctly reflected in the deserialized objects received by the object loader delegate. RestKit relies on naming and structure standards to simplify the code required to achieve the task. Your example deviates from key-value coding standards, so RK doesn't provide an easy way to interact with your data format.
If you don't have access or you can't change it, I think you'll need to map known key-value pairs with a mapping and perform the remaining assignments with a custom evaluator. You'd need to assume the unknown keys are actually name values for associated creators and their associated values contain the attribute hash for each. Using that, you'd then reconstruct each object manually.