XML to Object Objective C - ios

I'm trying to convert an XML response from Google to a custom object. My question is what's best to use as in NSMutableArray or NSDictionary when you have a multiple values in i.e. <category> or <title> and how to add them.
<category scheme="http://schemas.google.com/spreadsheets/2006"
term="http://schemas.google.com/spreadsheets/2006#spreadsheet"/>
<title type="text">nothing</title>

Marshaling XML onto a NSDictionary will work, however it can result in quite fragile and difficult to maintain code. Two reasons:
It will result - 'magic strings' when requesting data. Any change in this string will propagate throughout the code-base.
It will be difficult to read, and not exhibit the desirable self-documenting features of good OO.
Instead, its strongly recommended to map the XML of a service payload onto a use-case specific Objective-C object. This is aligned with the principle of contract-first development, meaning that any change to the service might only result in a change to this mapping onto the objective-C object.
A nice XML framework is RaptureXML
Create a category on the RXMLElement class and extract the required information. Then to use the element, just:
RXMLElement* element = [RXMLElement elementWith. . . ];
MyDomesticCat* type = [element asCat];

Any XML is ideally a combination on dictionaries and arrays with its root tag initiating a single key dictionary. To take off the overhead of parsing xml to a customized object model you can use the nice framework, XMLReader, available at github.
If you use this framework, your xml parsing becomes as simple as:
NSMutableDictionary* dictionary = [[XMLReader dictionaryForXMLData:<# your xml data #> error:&err] mutableCopy];
NSLog(#"%#",dictionary);
//use dictionary
[dictionary release];
However, you need to pass some well formed xml data as its input. Also you might need to manipulate the content of the parsed dictionary, according to your needs.

Related

Multiple KeyMappers per JSONModel

JSONModel lets you convert a model object into a NSDictionary as following:
NSDictionary *dict = [myJSONModel toDictionary]
It includes all properties of the model (except optional). However, I also need to create multiple dictionaries having only some model fields required for a particular backend operation.
Some fields could be included in multiple dictionaries, so ideally, it would be awesome if I could do something like:
NSDictionary *dictOne = [myJSONModel dictionaryWithKeyMapper:myJSONMapperOne]
NSDictionary *dictTwo = [myJSONModel dictionaryWithKeyMapper:myJSONMapperTwo]
and it only returns the objects that have been mapped in that particular mapper.
I am sure there's nothing like this at present. The keymapper for every class is created only once and then is cached, so you can't changed it programatically. Plus you cannot ignore properties via the keymapper.
JSONModel is built like so that it supposes you always need to do the same transformations when you convert between JSON and your model, this way it can do the performance optimisations it does.
However "toDictionary" is not too complicated, you could try subclassing JSONModel and playing around with implementing a "toDictionaryWithFieldList" that takes in field names list and exports only those fields ... just an idea

Serializing a custom object into NSDictionary or NSArray to use NSJSONSerialization

I've been looking for a way to serialize custom objects with NSJSONSerialization avoiding the use of third-party libraries, and I couldn't find any example. Is there any way of "automatically" create an NSDictionary and NSArray from an object, without having to create it typing in code all the object's member names yourself one by one and setting manually the values? I found a related post, but it is pretty old, things may have now changed.
Thanks
You can use KVC to ask any object for dictionaryWithValuesForKeys: which will give you a dictionary representation of the object.
If you need to change the property / key names then you want to do some mapping and (depending on what you're using the JSON for) you may find RestKit useful.

NSDictionary Vs. NSArray

I am reading on objective-c (a nerd ranch book), and I can't help thinking about this question: How do I decide which collection type, NSArray or NSDictionary (both with or w/o their mutable subclasses), to use when reading content from URL?
Let's say am reading JSON data from a PHP script (a scenario am dealing with), which to use? I know it is stated in many references that it depends on structure of data (i.e. JSON), but could a clear outline of the two structures be outlined?
Thank you all for helping :)
NSArray is basically just an ordered collection of objects, which can be accessed by index.
NSDictionary provides access to its objects by key(typically NSStrings, but could be any object type like hash table).
To generate an object graph from a JSON string loaded via a URL, you use NSJSONSerialization, which generates an Objective-C object structure. The resulting object depends on the JSON string. If the top-level element in your JSON is an array (starts with "["), you'll get an NSArray. If the top-level element is a JSON object (starts with "{"), you'll get an NSDictionary.
You want to use NSArray when ever you have a collection of the same type of objects, and NSDictionary when you have attributes on an object.
If you have, lets say a person object containing a name, a phone number and an email you would put it in a dictionary.
Doing so allows the order of the values to be random, and gives you a more reliable code.
If you want to have more then one person you can then put the person objects in an array.
Doing so allow you to iterate the user objects.
"withContentOfURL" or "withContentOfFile" requires the data in the URL or the file to be in a specific format as it is required by Cocoa. JSON is not that format. You can only use these methods if you wrote the data to the file or the URL yourself in the first place, with the same data. If you write an NSArray, you can read an NSArray. If you write an NSDictionary, you can read an NSDictionary. Everything else will fail.

How should I store a large number of nested dictionary information in iOS?

I have a large number of nested dictionaries and the leaf (or most nested) dictionaries store integer data and integer keys. All the information remains constant (but may change in a future release). I am currently allocating the dictionaries from constants in code but I feel I should be reading that information from XML or similar. I have read about Core information, plists, databases and archives but I don't want the user to be able to change it, I never want to be able to write it (except maybe during the release procedure) and I never want to display it. I would like to be able to hand edit it before release.
What is the best method to store this constant data?
Basically you need to ship your data in files with the app -
XML or JSON are both suitable for this. When I have had to do something similar I used JSON
It works something like this :
Define your JSON in text file (UTF8) and then use the
NSString initWithContentsOfFile to load file contents into a NSString
You can then use the NSJSONSerialization JSONObjectWithData to give you the top level dictionary for your JSON
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
From this you can extract your NSStrings / NSArrays using NSDictionary objectForKey for your data. Obviously the exact format will depend on your JSON format

Design/Implementation advice on XML Parsing with multiple connections/feeds/views

Starting my first iOS project and wanted to advice on how to structure the application.
The app pulls a XML feed, parses it out and displays a list representing the items in the XML feed. When clicking on a item in the list the app will pull a new XML feed using one of the attributes from the previously pulled XML feed. This happens several layers of pull, parse, display and on user selection do the same thing over again. Now most of the XML element structure is something like this:
(These are simple examples just to demonstrate what's going on)
http://site.com/get/items/
returns (Display info on new view):
<items>
<item id="123" name="item 1" />
<item id="124" name="item 2" />
<item id="125" name="item 3" />
</itmes>
http://site.com/get/description/123 (Example user has selected item 1, make call to get description)
returns:
<itemDescription>
<description itemId="123" name="desc 1" description="blah 1" />
</itemDescription>
Wanted to know:
Should I have a connection class/object or a new connection in each view?
Should I have a parser class/object or parse the XML feed in each view?
I'm also looking to store some of the data returned so I don't need to call the XML feed again if the user navigates back to the main items list, but I would need to parse the itemsDescription XML feed every time.
I've looked at several tutorials on parsing XML and I get the gist of how to do this, wanting to focus more of the design and reusability instead of duplicating the code over in each new view. Or am I way off on how this works
The best way you can do this following Apple Guidelines is checking one of their examples, some months ago I made an app similar to yours following this example. Also you can see how to make your app in offline mode.
Basic structure (w/o offline mode):
The SeismicXML sample application demonstrates how to use NSXMLParser
to parse XML data. When you launch the application it downloads and
parses an RSS feed from the United States Geological Survey (USGS)
that provides data on recent earthquakes around the world. It displays
the location, date, and magnitude of each earthquake, along with a
color-coded graphic that indicates the severity of the earthquake. The
XML parsing occurs on a background thread using NSOperation and
updates the earthquakes table view with batches of parsed objects.
Advanced structure (with offline mode):
Demonstrates how to use Core Data in a multi-threaded environment,
following the first recommended pattern mentioned in the Core Data
Programming Guide.
Based on the SeismicXML sample, it downloads and parses an RSS feed
from the United States Geological Survey (USGS) that provides data on
recent earthquakes around the world. What makes this sample different
is that it persistently stores earthquakes using Core Data. Each time
you launch the app, it downloads new earthquake data, parses it in an
NSOperation which checks for duplicates and stores newly founded
earthquakes as managed objects.
For those new to Core Data, it can be helpful to compare SeismicXML
sample with this sample and notice the necessary ingredients to
introduce Core Data in your application.
Regarding cwieland answer I wouldn't use ASIHTTPRequest because is outdated, so if you want to follow his approach I would recomend you to use AFNetworking, where you can handle an XML request easy and fast:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://api.flickr.com/services/rest/?method=flickr.groups.browse&api_key=b6300e17ad3c506e706cb0072175d047&cat_id=34427469792%40N01&format=rest"]];
AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
XMLParser.delegate = self;
[XMLParser parse];
} failure:nil];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[queue addOperation:operation];
Here is how I would implement it. I would use ASIHTTPRequest for all connection items and not worry about that part of it. It can handle all of your downloading of data asynchronous very easily with simple delegate methods.
I would have a parser class that takes in the url, downloads it asynchronously, and then parses the data returned. It would then return the array of parsed children through a delegate method to a tableview that would display the children in the xml data.
I would create a subclass of UITableViewController that will handle any url/data type in which case you'd only have to write up one tableview class and not worry about how the user navigates through. This would make it so that you only need to write one class and it would handle any number of drill downs or combinations. This implementation depends heavily on how complicated the distinct levels of xml data is. If they are drastically different it would make more sense to have cleaner code in the tableview and not have if's checking on the type of data in the cell creation.
Using a navigation style app would eliminate the need to re-parse the data each time the view loads as you pop views off the stack. Anytime going forward though it would be re-parsing but a simple cache of the urls->array could solve this if needed/wanted. It would require the reloading of the data each time the app launches though. Of course if you received a memory warning 3 levels deep it would require a re-parse or cache retrieval on your way back up.
If you are wanting a caching system I would write a class that goes in-between the view controllers and the url parser that checks the store and if it is in there return the array of data otherwise return nil and go get it.
I personally would use NSXMLParser as that is what I'm familiar with. You may want to house the elements in a class wrapper in which case you would just have to check which type of element you have on didStartElement and set an enum to switch on through creation. that is pretty easy with nsxmlparser. I haven't used any other parser to compare with but did find that debugging NSXMLParser was simple enough and coding was straightforward so it wasn't to hard to get it up and running. Here is a great site on all the different xml parsers:
http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project
So in summary I would have a subclass of NSObject that accepts the url, downloads it through ASIHTTPRequest, parses it. A Sublcass of UITableviewController that on the cell tap it allocates the same view controller class with the new url and pushes it on the navigation stack. The view would show a loading screen until the array is returned and then just reload the data. It would be a very DRY KISS hopefully.
I would house as much of the code in global classes as possible. If each pull of data there is only one main category, as in
<items>
<stuff></stuff>
....
<stuff></stuff>
</items>
EOF
I would use an array to house all the values, If there is more than one main section I would store everything in a dictionary with the parent attribute as the key and the values in an array. Then on the tableview have different sections based on the keys of the dictionaries.
I hope this answers some of your questions. I'm not sure how low of level you were looking for. I speak from developing quite a few apps and writing a RSS reader. Let me know if there is anything you'd like me to clarify.

Resources