I'm working with the Weather Underground API to make an app and I've hit a snag while parsing the block relating to severe alerts. The JSON uses key-value pairs that have sub key value pairs -- which haven't been a problem for me, as I can make subsequent NSDictionaries out of those -- but the entry for severe alerts has proven problematic. See below:
"alerts": [
{
"type": "WAT",
"description": "Flash Flood Watch",
"date": "3:13 PM EDT on April 28, 2012",
"date_epoch": "1335640380",
"expires": "8:00 AM EDT on April 29, 2012",
"expires_epoch": "1335700800",
"message": "\u000A...Flash Flood Watch in effect through Sunday morning...\u000A\u000AThe National Weather Service in Charleston has issued a\u000A\u000A* Flash Flood Watch for portions of northeast Kentucky... (Note: I trimmed this for length's sake),
"phenomena": "FF",
"significance": "A"
}
]
The "alerts" pair differs from others I've been able to parse because it has this [ ] bracket surrounding the sub-values and I'm not sure how to clear it so I can access the subvalues. In the other examples I've been able to parse, it only has the { } brackets, and not both the { } and [ ] brackets. For reference, the brackets are always present -- even when there are no severe weather alerts... in that instance the "alerts" pair returns the brackets [ ] with no sub-pairs present.
Is there a way I can remove the [ ] brackets from the NSDictionary, or otherwise ignore them? Any advice would be appreciated!
For reference and troubleshooting help, here's how I'm parsing the rest of the JSON document successfully:
1) Create an NSDictionary from the raw JSON
//Process Weather Call
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
2) Create subsequent dictionaries for nested json pairs
NSDictionary *current_observation = [json objectForKey:#"current_observation"];
3) Assign values
NSString* weather;
weather = [current_observation objectForKey:#"weather"];
So the end result would be a string that says "Partly Cloudy" or something, along with numerous related weather values that I haven't shown. These parse successfully because they only have the scope brackets { }, and not the [ ] brackets.
The brackets means the Json data there are in an array. You can parse it as following
NSArray *alertArray = [json objectForKey:#"alerts"];
now you should loop through all alerts and parse them (in your case it's only 1, but it could be more in another json string):
//parse each alert
for (NSDictionary *alert in alertArray ){
NSString* description = [alert objectForKey:#"description"];
//etc...
}
Okay, I got it working -- and I wanted to provide an example here because I ended up having to build on the advice #Lefteris gave to get it working.
I ended up having to pass the json array first as an NSArray, and then I converted that into an NSDictionary with the first element of the array. Everything afterwards worked as #Lefteris described.
So, in the end, here's what I've got:
NSArray *alerts = [json objectForKey:#"alerts"];
NSDictionary *alertDict = [[NSDictionary alloc] init];
//Check that no alerts exist to prevent crashing
if([alerts count] < 1) {
NSLog(#"No Alerts Here!");
type = nil;
...
}
else //Populate fields
{
alertDict = [alerts objectAtIndex:0];
for (NSDictionary *alert in alertDict)
{
NSLog(#"Printing alert!");
type = [alertDict objectForKey:#"type"];
...
}
}
This got me up and running with a single array iterate -- going on I expect I can simply iterate through the array since I know the count and handle any additional alerts. Thanks again for the help!
Related
I have the following situation:
NSDictionary *params = #{
#"Checkout" : #{
#"conditions" : #{#"Checkout.user_id" : #1},
#"order" : #{#"Checkout.id" : #"DESC"}
},
#"PaymentState" : #[],
#"Offer" : #[]
};
This dictionary contains params for a webservice request passing a JSON string with the webservice URL. I get the JSON string using NSJSONSerialization class, like this:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
The problem is: jsonString "keys" is ordered differently from the original params dictionary keys order, like this:
{
"Offer":[],
"PaymentState":[],
"Checkout":{
"conditions":{"Checkout.user_id":6},
"order":{"Checkout.id":"DESC"}
}
}
That is, the "PaymentState" and "Offer" keys come first in jsonString, and i need maintain
the original order. This is very important, like this:
{
"Checkout":{
"conditions":{"Checkout.user_id":6},
"order":{"Checkout.id":"DESC"}
},
"Offer":[],
"PaymentState":[]
}
So guys, how can i do that??
I use OrderedDictionary from CocoaWithLove whenever I need to keep the order of my dictionary keys.
Basically, OrderedDictionary contains an NSMutableDictionary and an NSMutableArray for the keys inside it, to keep track of the order of the keys. It implements the required methods for subclassing NSDictionary/NSMutableDictionary and just "passes" the method call to the internal NSMutableDictionary.
According to the JSON spec a JSON object is specifically unordered. Every JSON library is going to take this into account. So even when you get around this issue for now, you're almost certainly going to run into issues later; because you're making an assumption that doesn't hold true (that the keys are ordered).
While NSDictionary and Dictionary do not maintain any specific order for their keys, starting on iOS 11 and macOS 10.13, JSONSerialization supports sorting the keys alphabetically (see Apple documentation) by specifying the sortedKeys option.
Example:
let data: [String: Any] = [
"hello": "world",
"a": 1,
"b": 2
]
let output = try JSONSerialization.data(withJSONObject: data, options: [.prettyPrinted, .sortedKeys])
let string = String(data: output, encoding: .utf8)
// {
// "a" : 1,
// "b" : 2,
// "hello" : "world"
// }
I looked for a long time for an answer to this and couldn't find anything. Perhaps it is because I don't know how to ask the question as I am new to json. Essentially I am a new ios developer and am trying to learn how to access and use json data. Below is a portion of the json I am using:
{
"status": null,
"data": {
"1088": {
"nid": "1088",
"title": "RE 1 (2000)",
"articles": [
{
"nid": "2488",
"title": "Copyright Page"
},
...
etc.
my confusion is that there are two layers with the value title. So when I'm using something like
self.dict = [self getDictionaryFromJson]; and have saved the json in a dictionary, then I go to use
self.mainTitle = [self.dict objectForKey:#"title"]; and it would presumedly give me back RE 1 (2000). But then I also want to get back the secondary title which is Copyright Page so then i would do self.secondaryTitle = [self.dict objectForKey:#"title"];???
Anyways, my confusion is that I would think it would just again give me back RE 1 (2000) because there is no change to the call and so I don't know how to access the next item with the same key.
Perhaps I am sure the solution is simple I just don't quite understand what I need to do.
You are neglecting the hierarchy of the data which is mapped into the dict - log it to check.
So, to get the first title (RE 1 (2000)), you would do:
NSString *title = [self.dict valueForKeyPath:#"data.1088.title"];
to drill down through the levels in the JSON (and thus the dictionary). And the same approach applies for deeper nested items (though you can't always use valueForKeyPath: because it won't do what you expect with arrays...).
The JSON you posted contains nested arrays (denoted by square brackets []) and dictionaries (denoted by curly brackets {}). You can convert JSON to an NSDictionary using NSJSONSerialization:
NSData *data = ... // Get JSON Data
self.dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.mainTitle = [[[self.dict objectForKey:#"data"] objectForKey:#"1088"] objectForKey:#"title"]
self.secondaryTitle = [[[[[self.dict objectForKey:#"data"] objectForKey:#"1088"] objectForKey:#"articles"] objectAtIndex:0] objectForKey:#"title"]
For more info about JSON, you can read the spec.
Problem:
Every time, when I got a JSON string from Web Server, it looks like this:
{"array":[1,2,3],"boolean":true,"null":null,"number":123,"object":{"a":"b","c":"d","e":"f"},"string":"Hello World"}
I really wanna re-organise string format to NSLog() it like this:
{
"array": [
1,
2,
3
],
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"
},
"string": "Hello World"
}
Question:
Is there any shortcut to format JSON NSString with proper indentation and line feeds? (I know [NSDictionary description])
P.S.
Sometimes, the JSON NSString has prefix string like this:
Web Service response is : {"array":[1,2,3],"boolean":true,"null":null,"number":123,"object":{"a":"b","c":"d","e":"f"},"string":"Hello World"}
Any method or regular-expression can grab JSON string out of the paragraph?
Try this
NSData *data = [NSJSONSerialization dataWithJSONObject:temp options:NSJSONWritingPrettyPrinted error:nil ];
NSString* aStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"result: %#", aStr);
Here's some code that will strip leading characters up to the first curly brace and display the JSON data nicely formatted on the debug console.
NSRange range = [str rangeOfString:#"{"];
if ( range.location != NSNotFound )
str = [str substringFromIndex:range.location];
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog( #"%#", jsonData );
Try to parse it to an Object first and see what happens if you print it then. With a little luck the textual representation of Array's and Dictionaries will get you on your way. Right now you are printing a string, which will always look a little something like that.
Obviously you could write some code that recognizes the curly brackets and commas and based on that adds in line-endings and indentations. Should not be too hard, but the question is why would you want that?
If you use it to debug, just put a breakpoint there and look at the object in your code in XCode with the inspector. That will show you the object and the objects withing and give you an option to print it's representation to the console.
I m working on a chat application and i m getting a HTML response inside JSON response from server as chat History. Below is the response.
{ "status": "valid","chats": [{ "ces": "d5c15cf47d8e8684cfbebbc606f7d901", "fav":"0", "text": "<div class='ca'><i>sometext</i></div><><div class='ca'><b>prasad</b> has joined the chat.</div><><cid_1358766005><div class='co'><span class='notranslate'><b>prasad<timestamp_1358766041_co>:</b></span> hi</div></cid_1358766005><><div class='cl'><disconnected><d6>The party has left or disconnected. Chat session has ended.</div><>" } ] }
I want to separate them and Show in a table view.
I just tried to strip the HTML tag with the following category :
-(NSString *) stringByStrippingHTML {
NSRange r;
NSString *s = [self copy] ;
while ((r = [s rangeOfString:#"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
s = [s stringByReplacingCharactersInRange:r withString:#""];
return s;
}
But i m not getting all the data. I m never getting the timestamp. Please any one guide me How to get all the data.Thanks for your time.
You can use NSXMLParser. It's Apple's class for parsing XML documents.
Or else there are lot of open source libraries like TinyXML,Seismic XML etc for parsing XML documents.
Hope it Helps !!!
{"Overviews":
[
{"AAAA": [
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"}
],
"BBBB": [
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"}
]
}
]
}
Hi I used SBJson to parse this json. When I assigned NSArray *json = [jsonObject valueForKey:#"Overviews"];. The hierarchy of data didn't go well. I used one NSDictionary, 2 NSArray and 1 NSString to parse Generala.
My goal is to parse the data "Generala" like this:
NSDictionary *data = [overviews valueForObject:#"AAAA"];
NSString *generals = [data valueForObject:#"Generala"];
What have I done wrong in the json file? Thanks in advance.
You've got superfluous arrays in there. Overviews is an array with one element in - a dictionary. It should just be the dictionary. The same applies for AAAA and BBBB - they are arrays containing a single dictionary, when they should just be dictionaries.
Basically, just delete all of the square brackets in your JSON.
NSArray *dataArray = [overviews objectForKey:#"AAAA"];
NSDictionary *dataDict = [dataArray objectAtIndex:0];
NSString *generals = [dataDict objectForKey:#"Generala"];
This will get you to the correct value, But as you can see I had to "Hard code" the index "0". You would want some logic in there to get to the specific array.
or Change your json to:
{"Overviews":
{"AAAA":
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"},
"BBBB":
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"}
}
}
and use:
NSDictionary *dataDict = [overviews objectForKey:#"AAAA"];
NSString *string = [dataDict objectForKey:#"Generala"];
Your source is a dictionary of one entry, which entry contains an array of one entry, which entry contains a dictionary of two entries, which entries each contain an array of one entry, which entry contains a dictionary of three entries.
I suspect this is exactly how the JSON parser parsed it.