NSDictionary to XML - iphone

I'm trying to convert a NSDictionary to XML. (I was successful in transforming NSDictionary to JSON). But now I need to transform NSDictionary to XML. Is there a built-in serializer in Objective-C like the one for JSON?
int r = arc4random() % 999999999;
//simulate my NSDictionary (to be turned into xml)
NSString *name = [NSString stringWithFormat:#"Posted using iPhone_%d", r];
NSString *stock_no = [NSString stringWithFormat:#"2342_%d", r];
NSString *retail_price = #"12345";
NSArray *keys = [NSArray arrayWithObjects:#"name", #"stock_no", #"retail_price", nil];
NSArray *objects = [NSArray arrayWithObjects:name,stock_no,retail_price, nil];
NSDictionary *theRequestDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSDictionary *theFinalRequestDictionary = [NSDictionary dictionaryWithObject:theRequestDictionary forKey:#"product"];
...//other irrelevant code omitted
NSData *theBodyData = [NSPropertyListSerialization dataFromPropertyList:theFinalRequestDictionary format:NSPropertyListXMLFormat_v1_0 errorDescription:nil];
NSPropertyListFormat format;
id XMLed = [NSPropertyListSerialization propertyListFromData:theBodyData
mutabilityOption:NSPropertyListImmutable
format:&format
errorDescription:nil];
NSLog(#"the XMLed is this: %#", [NSString stringWithFormat:#"%#", XMLed]);
The NSLog doesn't print a string in XML format. It prints it like a NSDictionary.
What should I use to serialize my NSDictionary to XML?

propertyListFromData:... returns a "property list object", that is, depending on the contents of the data, an array or a dictionary. The thing that you're actually interested in (the xml) is returned by dataFromPropertyList:... and thus stored in your theBodyData variable.
Try this:
NSLog(#"XML: %#", [[[NSString alloc] initWithData:theBodyData encoding:NSUTF8StringEncoding] autorelease]);

There are many different varieties of XML. If you're not picky about the specific tags, and if the contents of your dictionary is limited to types used in property lists (NSString, NSNumber, NSDate, etc.) you can write your dictionary to a property list in one line:
[myDict writeToFile:somePath atomically:YES];
If you'd prefer to keep the XML in memory instead of writing to a file, use NSPropertyListSerialization as you're doing.

Related

Converting an NSArray of Dictionaries to JSON array in iOS

I need to send an NSArray to the server in the JSON array format. How can I convert it to JSON. This is a sample of my NSArray that I have to pass.
array([0] => array('latitude'=>'10.010490',
'longitude'=>'76.360779',
'altitude'=>'30.833334',
'timestamp'=>'11:17:23',
'speed'=>'0.00',
'distance'=>'0.00');
[1] => array('latitude'=>'10.010688',
'longitude'=>'76.361378',
'altitude'=>'28.546305',
'timestamp'=>'11:19:26',
'speed'=>'1.614',
'distance'=>'198.525711')
)`
and the required format is like this
[
{ "latitude":"10.010490",
"longitude":"76.360779",
"altitude":"30.833334",
"timestamp":"11:17:23",
"speed":"0.00",
"distance":"0.00"
},
{
"latitude":"10.010688",
"longitude":"76.361378",
"altitude":"28.546305",
"timestamp":"11:19:26",
"speed":"1.614",
"distance":"198.525711"
}
]
Any one have solution? Thanks in advance.
NSDictionary *firstJsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"10.010490", #"latitude",
#"76.360779", #"longitude",
#"30.833334", #"altitude",
#"11:17:23", #"timestamp",
#"0.00", #"speed",
#"0.00", #"distance",
nil];
NSDictionary *secondJsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"10.010490", #"latitude",
#"76.360779", #"longitude",
#"30.833334", #"altitude",
#"11:17:23", #"timestamp",
#"0.00", #"speed",
#"0.00", #"distance",
nil];
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr addObject:firstJsonDictionary];
[arr addObject:secondJsonDictionary];
NSData *jsonData2 = [NSJSONSerialization dataWithJSONObject:arr options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData2 encoding:NSUTF8StringEncoding];
NSLog(#"jsonData as string:\n%#", jsonString);
The simplest and best approach !!!
To convert NSArray or NSMutableArray into jsonString you can first convert it into NSData and then further convert that into a NSString. Use this code
NSData* data = [ NSJSONSerialization dataWithJSONObject:yourArray options:NSJSONWritingPrettyPrinted error:nil ];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
It helped me and hope it helps you as well. All the best.
I would recommend the SBJson-Framework.
Converting an NSMutableArray is as simple as NSString *jsonString = [yourArray JSONRepresentation];
Edit: Jack Farnandish is right u have to transform it into a NSDictionary before you can convert it to Json. In my example the NSMutableArray has to contain the Dictionary. The Array is only needed to create the square brackets at the beginning and the end of the string.
You can use the build in JSON functions of iOS or use an external lib e.g. JSONKit to convert your data to JSON
First You must change you structure into NSDictionary class and NSArray containing NSDictionary objects, then try JSONKit in iOS 5 serialization works better than standard NSJSONSerialization.
#import <JSONKit/JSON.h>
NSArray *array = // Your array here.
NSString *json = [array JSONString];
NSLog(#"%#", json);
JSONKit performs significantly better than SBJson and others in my own and the author's benchmarks.
Check this tutorial, JSON in iOS 5.0 was clearly explained (serailization, deserailization).
Is the service you are calling a RESTful service?
If so, I'd strongly recommend using RestKit. It does object serialization/deserialization. It also handles all the networking underpinnings. Extremely valuable, and well maintained.

value stored during initialization is never read

I am trying parse the google api so that I can retrieve the address and its data.
I get two errors that are on the commented lines. Why am I getting these errors.
I allocated the dit so I should have to release it correct.
Here is my code to retrieve the data
NSURL *url=[NSURL URLWithString:str];
NSData *data=[[NSData alloc]initWithContentsOfURL:url];
NSString *str1=[[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]autorelease];
NSDictionary *dit=[[[NSDictionary alloc]init]autorelease];//value stored to dit during initialization is never read
dit=[str1 JSONValue];
NSArray *dit1=(NSArray *) [dit objectForKey:#"results"];
NSDictionary *dit3=[[dit1 objectAtIndex:0]objectForKey:#"geometry"];
NSDictionary *dit4=[dit3 objectForKey:#"bounds"];
NSDictionary *northeast=[dit4 objectForKey:#"northeast"];
NSDictionary *lt=[northeast objectForKey:#"lat"];
NSDictionary *southwest=[dit4 objectForKey:#"southwest"];
NSDictionary *lng=[southwest objectForKey:#"lng"];
Probably the issue is this:
NSDictionary *dit=[[[NSDictionary alloc]init]autorelease];
dit=[str1 JSONValue];
You create an empty dictionary, then never use it but instead overwrite the value with the one returned from JSONValue. This code should be:
NSDictionary *dit=[str1 JSONValue];

Read/Write plist on iPhone iOS 5

I am studying iPhone development and facing a problem with a reading/writing plist file. I followed an example from a iPhone development book but keep getting an error message when running.
The error message says : 2012-04-26 00:21:09.759 FileHandling[5915:207] -[__NSCFDictionary addObject:]: unrecognized selector sent to instance 0x685ac40
Here is the example code (it seems fine to me...though):
NSString *plistFileName = [[self documentPath] stringByAppendingPathComponent: #"Apps.plist"];
NSLog(#"Where is the file? => %#", plistFileName);
if ([[NSFileManager defaultManager] fileExistsAtPath:plistFileName]) {
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistFileName];
for (NSString *category in dict) {
NSLog(#"%#", category);
NSLog(#"=========");
NSArray *titles = [dict valueForKey:category];
for (NSString *title in titles) {
NSLog(#"%#", title);
}
}
} else {
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Apps" ofType: #"plist"];
NSLog(#"%#", plistPath);
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile: plistPath];
NSLog(#"Let's take a look : %#", dict);
NSMutableDictionary *copyOfDict = [dict mutableCopy];
NSLog(#"Let's look at the mutable dictationary : %#", copyOfDict);
NSArray *categoriesArray = [[copyOfDict allKeys] sortedArrayUsingSelector: #selector(compare:)];
for (NSString *cateogry in categoriesArray) {
NSArray *titles = [dict valueForKey: cateogry];
NSMutableArray *mutableTitles = [titles mutableCopy];
[mutableTitles addObject: #"New App Title"];
[copyOfDict setObject: mutableTitles forKey:cateogry];
}
NSString *fileName = [[self documentPath] stringByAppendingPathComponent: #"Apps.plist"];
[copyOfDict writeToFile: fileName atomically:YES];
}
According to the error message, the problem is occurring in the call to addObject: on an __NSCFDictionary. This means that, at runtime, a dictionary received a message to add an object.
However, in this code snippet, addObject: is apparently being sent to an NSMutableArray. This probably means that each object titles you're retrieving from dict in the last for-loop is not an array, but in fact another dictionary, that your code is simply referring to as an array.
Indeed, your code does seem well-formed, so check the well-formedness of your source plist; open it up in a plain text editor. Also, you use a ton of logging, so confirm this way: in the output, dictionaries (including the root entry) are denoted by {curly = braces}, where arrays are denoted by (round parentheses).

JSONKit: changing and serializing JSON attribute's value

I am using JSONKit to parse JSON string into NSDictionary:
NSDictionary *deserializedData = [jsonString objectFromJSONString];
My question is: how can I change the dictionary values and get a changed JSON String?
I've tried to change the dictionary values:
[deserializedData setObject:[NSNumber numberWithInt:iRatings] forKey:#"ratings"];
But the app crashes in that line. What am I doing wrong?
Thanks in advance!
While the other answers are correct, what you really want in this case is:
NSMutableDictionary *deserializedData = [jsonString mutableObjectFromJSONString];
The mutableObjectFromJSONString method will create a mutable dictionary directly, which saves time and memory.
NSDictionary is an immutable dictionary, you need NSMutableDictionary to change the data. I'm not sure about JSONKit, but the built-in Cocoa JSON parser has a flag to return the data in mutable containers.
In worst case, you can do something like that:
NSMutableDictionary* data = [NSMutableDictionary dictionaryWithDictionary:[jsonString objectFromJSONString]];
[data setObject:[NSNumber numberWithInt:iRatings] forKey:#"ratings"];
//
// we begin with our string in json format
//
NSString *jsonString = [[NSString alloc] initWithString:#"{\"1\":\"Hole 1: Rossy Robinson - $25\",\"2\":\"Hole 7: Davey Ambrose - $25\",\"3\":\"Hole 14: Ross Robinson - $25\"}"];
//
// convert the json string to an NSMutableDictionary
//
NSError *e;
NSMutableDictionary *JSONdic = [NSJSONSerialization JSONObjectWithData: [jsonString dataUsingEncoding: NSUTF8StringEncoding] options: NSJSONReadingMutableContainers error: &e];
//
// change a value and add a new value in the dict
//
NSLog(#"before: object for key 1 is: %#", [JSONdic objectForKey:#"1"]);
[JSONdic setObject:#"xxx" forKey:#"1"];
[JSONdic setObject:#"Phil McQuitty" forKey:#"2"];
//
//convert dictionary object to json data
//
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:JSONdic options:NSJSONWritingPrettyPrinted error:&e];
//
// convert the json data back to a string
//
NSString *jsonText = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];\
//
// print out the final results
//
NSLog(#"back to string: %#", jsonText);
You try to change an immutableobject.
NSMutableDictionary *deserializedData = [NSMutableDictionary dictionaryWithDictionary: [jsonString objectFromJSONString]];
This is a mutable dictionary and you can change the values in it.
You try like this:
NSMutableDictionary *deserializedData = [NSMutableDictionary dictionaryWithDictionary: [jsonString objectFromJSONString]];
and then change the values:
[deserializedData setObject:[NSNumber numberWithInt:iRatings] forKey:#"ratings"];
For NSDictionary we cannot add or change values, thats why application is crashing.

Why NSMutableDictionary don't want write to file?

- (void)viewDidLoad
{
[super viewDidLoad];
if ([[NSFileManager defaultManager] fileExistsAtPath:pathString])
{
infoDict = [[NSMutableDictionary alloc] initWithContentsOfFile:pathString];
}
else
{
infoDict = [[NSMutableDictionary alloc]initWithObjects:[NSArray arrayWithObjects:#"BeginFrame",#"EndFrame", nil] forKeys:[NSArray arrayWithObjects:[NSNumber numberWithBool:YES],[NSNumber numberWithBool:YES], nil]];
if ([infoDict writeToFile:pathString atomically:YES])
{
NSLog(#"Created");
}
else
{
NSLog(#"Is not created");
NSLog(#"Path %#",pathString);
}
}
This is my code. I check if file is created, if not - I create a NSMutableDictionary and I write it to file at path, but writeToFile method returns NO. Where is problem? If I create this file with NSFileManager it works, but doesn't when I want to write a dictionary.
writeToFile:atomically only works if the dictionary you call it on is a valid property list object (see docs).
For a NSDictionary to be a valid property list object, among other things, its keys must be strings, but in your example the keys are NSNumber instances.
You can not control the content you are going to write sometimes. For example, you can't avoid a null value when you are going to write a JSON object that is gotten from a server.
NSData is compatible with these "invalid" values, so converting NSArray or NSDictionary to NSData is an ideal way in these cases.
write:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonObject];
[data writeToFile:path atomically:YES];
read:
NSData *data = [NSData dataWithContentsOfFile:path];
NSDictionary *jsonObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];