I am a beginner in objective C , I want to parse a XML file from URL , I found some sample code about NSXMLPARSER and I write this code but it do not work.
please help me.
my xml file is :
<list>
<first>apple</first>
</list>
... My ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <NSXMLParserDelegate> {
}
#property (weak, nonatomic) IBOutlet UITextView *myTextField;
#end
...My ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController #synthesize myTextField;
- (void)parseXMLFileAtURL:(NSString *)URL {
NSURL * xmlURL = [NSURL URLWithString:URL];
NSXMLParser * rssparser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[rssparser setDelegate:self];
[rssparser parse];
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary*)attributeDict {
if ([elementName isEqualToString:#"list"]) {
// clear out our story item caches...
myTextField.text = [attributeDict objectForKey:#"first"];
}
}
- (void)viewDidLoad {
NSString * path = #"http://example.com";
[self parseXMLFileAtURL:path];
[super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload {
[self setMyTextField:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
You shouldn't declare this is ViewController - is a very bad design. Create a new class (ex XMLParser: #interface XMLParser : NSObject <NSXMLParserDelegate>)
Now call in the initializer method parse. Below sample code:
-(id)init
{
self = [super init];
parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"guidef" ofType:#"xml"]]];
[parser setDelegate:self];
[parser parse];
return self;
}
Now you can declare your methods.
attributeDict holds only attribute values ...
<first name="something" last="something" > <sec>some</sec></first>
so when you get elementName as first attributeDict will have 'name' and 'last' and other attributes
not the child element sec
Related
I am using NSXMLParser to grab information from an online XML file. My goal is to have one class do the XML parsing and another class to implement the variables. Below is the code for my project:
Current.h & Current.m
#import <Foundation/Foundation.h>
#interface Current : NSObject {
NSString *curTempF;
IBOutlet NSTextField *textField;
}
#property (nonatomic, copy) NSString *curTempF;
- (void)displayOutlets:(id)sender;
#end
and
#import "Current.h"
#implementation Current
#synthesize curTempF;
- (void)awakeFromNib {
[self displayOutlets:self];
}
- (void)displayOutlets:(id)sender {
[textField setStringValue:curTempF];
}
#end
XmlParser.h & XmlParser.m
#import <Foundation/Foundation.h>
#interface XmlParser : NSObject <NSXMLParserDelegate> {
NSString *urlString;
NSURL *url;
NSMutableString *xmlString;
}
- (IBAction)fetchXML:(id)sender;
#end
and
#import "XmlParser.h"
#import "Current.h"
#implementation XmlParser
- (void)awakeFromNib {
[self fetchXML:self];
}
- (IBAction)fetchXML:(id)sender {
urlString = #"http://api.wunderground.com/api/***/conditions/q/28173.xml";
url = [NSURL URLWithString:urlString];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqual:#"temp_f"]) {
xmlString = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqual:#"temp_f"]) {
Current *cTempF = [[Current alloc] init];
[cTempF setCurTempF:xmlString];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
[xmlString appendString:string];
}
#end
When I run the program I am receiving an error about "Invalid parameter not satisfying: aString". It looks like the setStringValue for the IBOutlet is not working. Any suggestions?
I suspect that when you initialize the Current class with [[Current alloc] init], it is trying to populate the textField with the curTempF string. However, the curTempF string is not initialized yet at that point until you call [cTempF setCurTempF:xmlString].
One approach would be to not display outlets in the Current class:
- (void)awakeFromNib {
//[self displayOutlets:self];
}
Then, call the displayOutlets function in your parser:
if ([elementName isEqual:#"temp_f"]) {
Current *cTempF = [[Current alloc] init];
[cTempF setCurTempF:xmlString];
[cTempF displayOutlets:cTempF];
}
Alternately, you could keep your awakeFromNib code the same, but create an initWith method in your Current class, which may be cleaner:
- (id) initWithCurTemp:(NSString *)curTemp {
self = [super init];
if (self) {
self.curTempF = curTemp;
}
return self;
}
- (void)awakeFromNib {
[self displayOutlets:self];
}
Then, your parser code would look like:
if ([elementName isEqual:#"temp_f"]) {
Current *cTempF = [[Current alloc] initWithCurTemp:xmlString];
}
You should create your Current in the nib, as you were doing, and not in code.
As for getting the parser (which I assume is in the same nib) to talk to the Current, create an outlet in the parser to point to the Current, and connect that outlet in the nib.
I'm getting the following error:
"this class is not key value coding-compliant for the key temp_f"
my AppDelegate class files:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSTableView *tableView;
NSArray *current;
}
#property (assign) IBOutlet NSWindow *window;
#end
#import "AppDelegate.h"
#import "CurrentWeather.h"
#import "XMLCurrent.h"
#implementation AppDelegate
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
XMLCurrent *currentXML = [[XMLCurrent alloc] init];
NSError *error = nil;
current = [currentXML fetchCurrentWithError:&error];
[tableView reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)theTableView {
return [current count];
}
- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
CurrentWeather *c = [current objectAtIndex:row];
return [c valueForKey:[tableColumn identifier]];
}
#end
my CurrentWeather class files:
#import <Foundation/Foundation.h>
#interface CurrentWeather : NSObject {
NSString *location;
NSString *weather;
NSString *degreesF;
}
#property (nonatomic, copy) NSString *location;
#property (nonatomic, copy) NSString *weather;
#property (nonatomic, copy) NSString *degreesF;
#end
#import "CurrentWeather.h"
#implementation CurrentWeather
#synthesize location, weather, degreesF;
#end
my XMLCurrent class files:
#import <Foundation/Foundation.h>
#interface XMLCurrent : NSObject <NSXMLParserDelegate> {
NSMutableArray *current;
NSMutableString *currentString;
NSMutableDictionary *currentFields;
}
- (NSArray *)fetchCurrentWithError:(NSError **)outError;
#end
#import "XMLCurrent.h"
#import "CurrentWeather.h"
#implementation XMLCurrent
- (id)init {
self = [super init];
if (self) {
current = [[NSMutableArray alloc] init];
}
return self;
}
- (NSArray *)fetchCurrentWithError:(NSError **)outError {
BOOL success;
NSURL *xmlURL = [NSURL URLWithString:#"http://www.weather.gov/xml/current_obs/KCLT.xml"];
NSURLRequest *req = [NSURLRequest requestWithURL:xmlURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
NSURLResponse *resp = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&resp error:outError];
if (!data) {
return nil;
}
[current removeAllObjects];
NSXMLParser *parser;
parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
success = [parser parse];
if (!success) {
*outError = [parser parserError];
return nil;
}
NSArray *output = [current copy];
return output;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
if ([elementName isEqual:#"current_observation"]) {
currentFields = [[NSMutableDictionary alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqual:#"current_observation"]) {
CurrentWeather *currentCond = [[CurrentWeather alloc] init];
[currentCond setLocation:[currentFields objectForKey:#"location"]];
[currentCond setWeather:[currentFields objectForKey:#"weather"]];
[currentCond setDegreesF:[currentFields objectForKey:#"temp_f"]];
[current addObject:currentCond];
currentCond = nil;
currentFields = nil;
} else if (currentFields && currentString) {
NSString *trimmed;
trimmed = [currentString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[currentFields setObject:trimmed forKey:elementName];
}
currentString = nil;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentString) {
currentString = [[NSMutableString alloc] init];
}
[currentString appendString:string];
}
#end
The keys are used as the "identifier" in a table view. For some reason, if the key has an underscore in it (such as temp_f) I get an error. The underscore is necessary because it is the name of the element in the XML file. If there is no underscore, then no error. How can I get data from an XML element that contains an underscore?
The xml data is being parsed from http://www.weather.gov/xml/current_obs/KCLT.xml
CurrentWeather has a degreesF property, which you set from the temp_f XML field. You need to set the identifier for the table column to "degreesF" not "temp_f". This has nothing to do with temp_f containing an underscore. Rather, the problem is that CurrentWeather isn't Key Value Coding compliant for the key "temp_f" (just as the error states) because it doesn't have a property named "temp_f".
Explaining in further detail, in your -tableView:objectValueForTableColumn: method, you use the column's identifier as a key into a CurrentWeather instance. Since the identifier is "temp_f", you're doing this: [c valueForKey:#"temp_f"]. That throws an exception because CurrentWeather doesn't have a temp_f property.
I have a tag <AboutUs> (having HTML tags) and I have stored the string part in a local string. Now I want to pass it to my webView to display, but it is showing my string (null).
Here's my code, any help is appreciated:
#class AppDelegate_iPhone;
#interface AboutUsViewController : UIViewController<NSXMLParserDelegate> {
NSMutableString *aboutUsString;
NSString *currentElement;
IBOutlet UIWebView *webView;
AppDelegate_iPhone *appDelegate;
}
#property(nonatomic,retain) NSMutableString *aboutUsString;
#property(nonatomic,retain) IBOutlet UIWebView *webView;
-(id)init;
#end
#implementation AboutUsViewController
#synthesize aboutUsString,webView;
-(id)init{
if(self == [super init]){
aboutUsString = [[NSMutableString alloc]init];
}
return self;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
NSURL *url = [[NSURL alloc] initWithString:#"http://mobileecommerce.site247365.com/admin/AboutUs.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
AboutUsViewController *parser = [[AboutUsViewController alloc] init];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
NSLog(#"After Parsing=== = = = = = = = == = = = = %#",appDelegate.TextString);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
currentElement = elementName;
if([currentElement isEqualToString:#"AboutUs"]) {
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if([currentElement isEqualToString:#"AboutUs"]) {
NSMutableString *outputBuilder = [[NSMutableString alloc]init] ;
[outputBuilder appendString:[NSString stringWithFormat:#"%#", self.aboutUsString]];
[outputBuilder appendString:[NSString stringWithFormat:#"%#", string]];
self.aboutUsString = outputBuilder;
[outputBuilder release];
}
else
{
self.aboutUsString = string;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"AboutUs"]) {
[webView setScalesPageToFit:YES];
[webView loadHTMLString:self.aboutUsString baseURL:[NSURL URLWithString:#"http://www.hitchhiker.com/message"]];
NSLog(#"In DID End Element ===== %#",aboutUsString);
appDelegate.TextString = [[NSMutableString alloc]initWithString:aboutUsString];
}
currentElement = #"";
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"In Document End ========= %#",aboutUsString);
NSLog(#"Appdelgate Text String %#",appDelegate.TextString);
}
- (void)dealloc {
[super dealloc];
[webView release];
}
#end
In your viewDidLoad method, you're creating a new AboutUsViewController which then gets all the NSXMLParser delegate calls. It has its own web view, that one will load the parsed HTML, but you'll never see it because the parsing view controller is never actually visible.
You should set self as the xml parser's delegate instead of creating a new instance.
I would like to look through the elements of a file and when one specific element comes out, output the contents in between the tag.
I tried to follow the example in the Mac Dev entitled Event Driven XML Programming, but it just doesn't finish very clearly. It says to make sure I code the delegates, but it never shows an example. I just want to see a simple example where:
The file is assumed to be a good xml file.
Its path is a URL (or string).
The way the delegate interacts with the parser is explained.
Many tutorials for Cocoa seem to almost teach you to circumvent the delegate classes and make your own IBAction functions so I'm missing the training I think on how to use the delegates properly. Its not clear in the example if I'm supposed to build the delegates in the delegate class or keep them in the class with the parser.
This is based on something I originally wrote for Cut out a part of a long NSString. I copied the NSXMLParserDelegate code from that iOS project into an OS X project. It gets the text from a specific object in a web page.
.h file:
#interface so7576593AppDelegate : NSObject <NSApplicationDelegate, NSXMLParserDelegate> {
NSWindow *window;
IBOutlet NSTextField *textField;
NSMutableString *divCharacters;
BOOL captureCharacters;
}
#property (assign) IBOutlet NSWindow *window;
#end
.m file:
#import "so7576593AppDelegate.h"
#implementation so7576593AppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
captureCharacters = NO;
NSURL *theURL = [NSURL URLWithString:#"http://maxnerios.yolasite.com/"];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:theURL];
[parser setDelegate:self];
[parser parse];
[parser release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqual:#"div"] && [[attributeDict objectForKey:#"id"] isEqual:#"I3_sys_txt"]) {
captureCharacters = YES;
divCharacters = [[NSMutableString alloc] initWithCapacity:500];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (captureCharacters) {
//from parser:foundCharacters: docs:
//The parser object may send the delegate several parser:foundCharacters: messages to report the characters of an element.
//Because string may be only part of the total character content for the current element, you should append it to the current
//accumulation of characters until the element changes.
[divCharacters appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (captureCharacters) {
captureCharacters = NO;
[textField setStringValue:divCharacters];
[divCharacters release];
}
}
#end
If you click the "Next" link on that page and go onto "Handling XML Elements and Attributes" it will give you an example of how to code the delegates.
Apple provides a Mac example in ImageMap.
There's no difference between NSXMLParser on Mac and iPhone, so reading an iPhone example shouldn't be a problem.
Here is an example of using an NSXMLParser in a custom class that takes in a string of the tag to look for and the xml NSData:
JHXMLParser.h:
#protocol JHXMLParserDelegate <NSObject>
#optional
- (void)acceptParsedData:(NSMutableArray *)parsedData withIdent:(NSString *)ident;
- (void)acceptParsedDebugData:(NSMutableArray *)parsedData withIdent:(NSString *)ident;
#end
#class JHKeyValuePair;
#interface JHXMLParser : NSObject <NSXMLParserDelegate> {
NSString *ident;
#private
id _delegate;
NSMutableArray *_parsedData;
NSString *_key;
NSData *_rawData;
NSXMLParser *_dataParser;
NSString *_previousTag;
NSString *_currentTag;
}
#property (retain, nonatomic) NSString *ident;
- (id)initWithKeyValuePair:(JHKeyValuePair *)kvPair;
- (id)initWithKey:(NSString *)Key andData:(NSData *)data;
// delegate management. The delegate is not retained.
- (id <JHXMLParserDelegate>)delegate;
- (void)setDelegate:(id <JHXMLParserDelegate>)delegate;
- (BOOL)start;
#end
And the JHXMLParser.m:
#import "JHKeyValuePair.h"
#import "JHXMLParser.h"
#implementation JHXMLParser
#synthesize ident;
- (id)init {
if ((self = [super init])) {
ident = [[NSString alloc] init];
}
return self;
}
- (id)initWithKeyValuePair:(JHKeyValuePair *)kvPair {
if ((self = [self init])) {
_key = [kvPair key];
_rawData = [kvPair value];
_dataParser = [[NSXMLParser alloc] initWithData:_rawData];
_dataParser.delegate = self;
}
return self;
}
- (id)initWithKey:(NSString *)key andData:(NSData *)data {
if ((self = [self init])) {
_key = key;
_rawData = data;
_dataParser = [[NSXMLParser alloc] initWithData:_rawData];
_dataParser.delegate = self;
}
return self;
}
- (id <JHXMLParserDelegate>)delegate {
id <JHXMLParserDelegate> d = nil;
if (_delegate) {
d = _delegate;
}
return d;
}
- (void)setDelegate:(id <JHXMLParserDelegate>)delegate {
_delegate = delegate;
}
- (BOOL)start {
return [_dataParser parse];
}
- (void)dealloc {
[_parsedData release];
[_rawData release];
[super dealloc];
}
#pragma mark - NSXMLParser Delegate
- (void)parserDidStartDocument:(NSXMLParser *)parser {
_parsedData = [[NSMutableArray alloc] init];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
_currentTag = elementName;
if ([elementName isEqualToString:_key]) {
NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] init];
[_parsedData addObject:tmpDict];
[tmpDict release];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (![_previousTag isEqualToString:_currentTag]) {
[[_parsedData lastObject] setObject:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
forKey:_currentTag];
} else {
[[_parsedData lastObject] setObject:[NSString stringWithFormat:#"%#%#",[[_parsedData lastObject] objectForKey:_currentTag], [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]
forKey:_currentTag];
}
if (_previousTag) {
[_previousTag release];
_previousTag = nil;
}
_previousTag = [[NSString alloc] initWithFormat:#"%#", _currentTag];
[pool drain];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (![_previousTag isEqualToString:elementName]) {
[[_parsedData lastObject] setObject:#"" forKey:elementName];
} else {
if (_previousTag) {
[_previousTag release];
_previousTag = nil;
}
_previousTag = [[NSString alloc] initWithFormat:#""];
}
[pool drain];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
if ([_delegate respondsToSelector:#selector(acceptParsedData:withIdent:)]) {
[_delegate acceptParsedData:_parsedData withIdent:ident];
} else if ([_delegate respondsToSelector:#selector(acceptParsedDebugData:withIdent:)]) {
[_delegate acceptParsedDebugData:_parsedData withIdent:ident];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
#ifdef DEBUG
DEBUGLOG(#"Parser ERROR Occurred: %#", self.ident);
DEBUGLOG(#"ERROR: %#", parseError);
#endif
if ([_delegate respondsToSelector:#selector(acceptParsedData:withIdent:)]) {
[_delegate acceptParsedData:_parsedData withIdent:ident];
} else if ([_delegate respondsToSelector:#selector(acceptParsedDebugData:withIdent:)]) {
[_delegate acceptParsedDebugData:_parsedData withIdent:ident];
}
}
#end
Used like so:
parser = [[[JHXMLParser alloc] initWithKey:#"INFO" andData:connectData] autorelease];
parser.ident = #"INFO";
parser.delegate = self;
[parser start];
Then implement the delegate method:
- (void)acceptParsedData:(NSMutableArray *)parsedData withIdent:(NSString *)ident {
// do stuff here with the parsed data
}
I use an instance of NSXMLParser. I store found chars in NSMutableStrings that are stored in an NSMutableDictionary and these Dicts are then added to an NSMutableArray.
When I test this everything seems normal: I count 1 array, x dictionnaries and x strings.
In a detailview controller file I want to show my parsed results. I call the class where everthing is stored but I get (null) returned.
This is what I do (wrong):
xAppDelegate.h
#interface xAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
xAppDelegate.m
#import "xAppDelegate.h"
#import "RootViewController.h"
#import "XMLParser.h"
#implementation xAppDelegate
#synthesize window, navigationController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// OFFLINE DOCUMENT > Resources folder
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *DataPath = [Path stringByAppendingPathComponent:#"file.xml"];
NSData *Data = [[NSData alloc] initWithContentsOfFile:DataPath];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:Data];
XMLParser *parser = [[XMLParser alloc] initXMLParser];
[xmlParser setDelegate:parser];
[xmlParser setShouldProcessNamespaces:NO];
[xmlParser setShouldReportNamespacePrefixes:NO];
[xmlParser setShouldResolveExternalEntities:NO];
[xmlParser parse];
[window addSubview: navigationController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[window release];
[navigationController release];
[super dealloc];
}
#end
XMLParser.h
#class xAppDelegate;
#interface XMLParser : NSObject {
NSMutableArray *array;
NSMUtableDictionary *dictionary;
NSSMutabletring *element;
xAppDelegate *appDelegate;
}
- (XMLParser *) initXMLParser;
#property (nonatomic, retain) NSMutableArray *array;
#property (nonatomic, retain) NSMutableDictionary *dictionary;
#property (nonatomic, retain) NSMutableString *element;
XMLParser.m
#import "xAppDelegate.h"
#import "XMLParser.h"
#synthesize array, dictionary, element;
- (XMLParser *) initXMLParser {
[super init];
appDelegate = (xAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parserDidStartDocument:(NSXMLParser *)parser {
array = [[NSMutableArray alloc] init];
dictionary = [[NSMutableDictionary alloc] init];
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
ele = [elementName copy];
if ([elementName isEqualToString:#"CONTAINER"]) {
element = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSMutableString *)string
{
if ([ele isEqualToString:#"ELEMENTNAME"]) {
[element appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"CONTAINER"]) {
[dictionary setObject:element forKey:#"ELEMENTNAME"];
[array addObject:[dictionary copy]];
}
}
- (void) dealloc {
[element release];
[dictionary release];
[array release];
}
In my controller file I do this:
controller.h
#class XMLParser;
#interface controller : UIViewController {
XMLParser *aXMLParser;
}
#property (nonatomic, retain) XMLParser *aXMLParser;
controller.m
#import "XMLParser.h"
#synthesize aXMLParser;
- (void)viewDidLoad {
NSLog(#"test array: %#", aXMLParser.array);
NSLog(#"test dict: %#", aXMLParser.dictionary);
NSLog(#"test element: %#", aXMLParser.element);
}
When I test the value of my array, a dict or an element in the XMLParser.h file I get my result. What am I doing wrong so I can't call my results in my controller file?
Any help is welcome, because I'm pretty stuck right now :/
You probably haven't initialised the NSMutableString element, so you are probably sending messages to a nil object.
That's a guess because you haven't posted the important code. We need to see
where you initialise the three objects
where you assign them e.g. you might be assigning nil to one of them without realising it.
Edited following latest bit of code
There's quite a lot wrong with the code, for instance, it leaks a lot of objects, but I can't see anything that would cause your specific issue, unless the the ELEMENTNAME elements don't appear inside the CONTAINER elements in your XML.
I'm not an expert on user interface code on iPhone, but are you sure applicationDidFinishLaunching runs before viewDidLoad?
Also, you don't seem to ever assign your parser to the aXMLParser property.
Some of the Other Issues
Your NSXMLParser leaks because you don't release it.
Your own parser also leaks for the same reason (you probably just want to use aXMLParser, not a locally defined one).
Your initXMPLarser method should look like:
- (XMLParser *) initXMLParser {
self = [super init];
if (self != nil)
{
appDelegate = (xAppDelegate *)[[UIApplication sharedApplication] delegate];
}
return self;
}
i.e. don't throw away the result of [super init] and make sure it is not nil.
array is allocated every time you hit a new element. Each tilme you hit a new element, you throw away and leak the previous array from the last element.
dictionary is allocated every time you hit a CONTAINER element. You should at least release the old one before allocating the new one.
element also leaks.
The copy of dictionary you put into the array also leaks. Objective-C collections retain their elements.