IOS and XML parser (reading file ) - iphone

I am new in IOS. and i was looking for a tuto or small example in how to read from a local xml file in my ressources but i found nothing....any one with a good tuto or have worked with xml before i really need your help

Here you have the NSXMLParserDelegate doc with examples

You can use the following code for reading the xml file:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"myLocalXML" ofType:#"xml"];
if (filePath)
{
NSString *myText = [NSString stringWithContentsOfFile:filePath];
if (myText)
{
NSLog(#"XML : %#",myText);
NSData *xmlData = [myText dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
parser.delegate = self;
[parser parse];
}
}

the following link will help you adding parser provided by apple
http://www.edumobile.org/iphone/iphone-programming-tutorials/parsing-an-xml-file/
NSString *path = [[NSBundle mainBundle] pathForResource:#"Name of your xml here...." ofType:#"xml"];
use the e above code to access file from your project and provide it to above parser for parsing

TBXML is my favorite. You can download project from git hub.
And why is this my favorite is because it's easy to understand and also it's performance is high.
Read this blog for more
How To Choose The Best XML Parser for Your iPhone Project

Related

CHCSV Error : unable to allocate memory for length

I want to parse a .csv file. For this I use the CHCSV Parser. But when I push into the view where the parser should start parsing, the app crashes.
Terminating app due to uncaught exception 'NSMallocException', reason:
'* -[NSConcreteMutableData appendBytes:length:]: unable to allocate
memory for length (4294967295)'
NSString *filePath = #"http://somewhere.com/test.csv";
NSString *fileContent = [NSString stringWithContentsOfURL:[NSURL URLWithString:filePath] encoding:NSUTF8StringEncoding error:nil];
self.csvParser = [[CHCSVParser alloc] initWithContentsOfCSVFile:fileContent];
Edit:
I'm developing for iOS 6+. Thanks for the great comments and answers. I hope to get the right solution.
Input Stream
It doesn't work. When I want to work with the input stream the app crashes because of the wrong encoding.
Incompatible integer to pointer conversion sending 'int' to
parameter of type 'NSStringEncoding *' (aka 'unsigned int *')
NSData *downloadData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://example.com/test.csv"]];
NSInputStream *stream = [NSInputStream inputStreamWithData:downloadData];
self.csvParser = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:NSUTF8StringEncoding delimiter:#";"];
self.csvParser.delegate = self;
[self.csvParser parse];
CSV-String
NSString *filePath = #"http://example.com/test.csv";
NSString *fileContent = [NSString stringWithContentsOfURL:[NSURL URLWithString:filePath] encoding:NSUTF8StringEncoding error:nil];
self.csvParser = [[CHCSVParser alloc] initWithCSVString:fileContent];
self.csvParser.delegate = self;
[self.csvParser parse];
This parse only (null).
Final Edit: Dave, the author of CHCSVParser, updated his code on github, so this problem should be solved when you use the most recent version. Get it now!
Okay, here we go:
First add the following code in CHCSVParser.m:
In method - (void)_sniffEncoding at the very beginning you have:
uint8_t bytes[CHUNK_SIZE];
NSUInteger readLength = [_stream read:bytes maxLength:CHUNK_SIZE];
[_stringBuffer appendBytes:bytes length:readLength];
[self setTotalBytesRead:[self totalBytesRead] + readLength];
change it to:
uint8_t bytes[CHUNK_SIZE];
NSUInteger readLength = [_stream read:bytes maxLength:CHUNK_SIZE];
if (readLength > CHUNK_SIZE) {
readLength = CHUNK_SIZE;
}
[_stringBuffer appendBytes:bytes length:readLength];
[self setTotalBytesRead:[self totalBytesRead] + readLength];
After that changed I got only null values so I changed the file path (in the sample project it is located in the main(), however I did the parsing in viewDidLoad.
Make sure you copied the file in your bundle directory for that to work!
file = [NSBundle pathForResource:#"Test" ofType:#"scsv" inDirectory:[[NSBundle mainBundle] bundlePath]];
Edit:
When you say you need to download the file you can do following (but notice that this is quick and dirty solution especially on mobile devices)
NSData *downloadData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.yourdomain.tld/Test.scsv"]];
NSInputStream *stream = [NSInputStream inputStreamWithData:downloadData];
The last line is the important one here you need to change.
Hope that solves your issue.
Edit 2:
I've just created a repository with a demo project for you where the code actually works. Perhaps you can find out what you do wrong (or at least different). Here is the link.
Edit 3:
Change
self.csvParser = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:NSUTF8StringEncoding delimiter:#";"];
to
self.csvParser = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:&encoding delimiter:';'];

.js file not stored in package contents

I am using .js file to validate .html file in my application,the .js&.html files added in my project,but the .js file not stored in package contents,only contains the .html file,I am using ios simulator 5.0,
my validation source is..
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *urlAddress = [[NSBundle mainBundle] pathForResource:#"index"
ofType:#"html"]; //you can also use PDF files
NSLog(#"%#",urlAddress);
NSURL *url = [NSURL fileURLWithPath:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[web loadRequest:requestObj];
web.backgroundColor=[UIColor redColor];
}
- (IBAction)markHighlightedString:(id)sender {
// The JS File
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"HighlightedString" ofType:#"js" inDirectory:#""];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
NSString *jsString = [[NSMutableString alloc] initWithData:fileData encoding:NSUTF8StringEncoding];
[web stringByEvaluatingJavaScriptFromString:jsString];
// The JS Function
NSString *startSearch = [NSString stringWithFormat:#"stylizeHighlightedString()"];
[web stringByEvaluatingJavaScriptFromString:startSearch];
}
- (IBAction)getHighlightedString:(id)sender {
// The JS File
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"HighlightedString" ofType:#"js" inDirectory:#""];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
NSString *jsString = [[NSMutableString alloc] initWithData:fileData encoding:NSUTF8StringEncoding];
[web stringByEvaluatingJavaScriptFromString:jsString];
// The JS Function
NSString *startSearch = [NSString stringWithFormat:#"getHighlightedString()"];
[web stringByEvaluatingJavaScriptFromString:startSearch];
NSString *selectedText = [NSString stringWithFormat:#"selectedText"];
NSString * highlightedString = [web stringByEvaluatingJavaScriptFromString:selectedText];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Highlighted String"
message:highlightedString
delegate:nil
cancelButtonTitle:#"Oh Yeah"
otherButtonTitles:nil];
[alert show];
//[alert release]; // not required anymore because of ARC
}
- (IBAction)removeAllHighlights
{
// calls the javascript function to remove html highlights
[web stringByEvaluatingJavaScriptFromString:#"uiWebview_RemoveAllHighlights()"];
}
I am getting null value in NSLog(#"%#",filePath);//HighlightedString.js
I'm not totally sure, but could it be that you haven't copied that file to the target's output? Or, that you're using an out-dated version of the app that's being run? An easy fix might be just to do a Clean and then a Build and Run. Also, the file might be not be set to go into the target. You can change that by going to Target > Build Phases > Copy Bundle Resources. This will bring up an area where you can add that file.
Following that, I usually do a Clean and then a Build just to make sure I'm getting a new version of the application.
Addition
Also, you might try setting the inDirectory: part of the method where you're setting filePath to nil instead of specifying an empty string. Or, you could just get rid of that altogether and [[NSBundle mainBundle] pathForResource:#"HighlightedString" ofType:#"js"]
You can try these two options
1- click on js file in the project navigator then in the properties you needd to check a check box to include it in the build. This image I made before check step one and four only.
2- just write the JavaScript into the HTML file and put it inside function and call this function and stop loading it as text. So stringByEval.... Will take the JavaScript function only.

How to convert csv file data into NSMutabledictionary

I want to parse the csv data with live link and convert the same in NSMutabledictionary.Here is the link that i am using for csv file.
http://ichart.yahoo.com/table.csv?s=BAS.DE&d=2&e=30&c=2012
Please help me out for the same.
Thanks in advance.
This link should have what you need. But, do you download that link as file into your app directory? If so, after importing parseCSV, it is fairly easy to go through the lines of the csv file:
CSVParser *parser = [CSVParser new];
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"myCsvFile" ofType:#"csv"];
[parser openFile:csvFilePath];
NSArray *csvContentArray = [parser parseFile];
for (int i=0; i<csvContentArray.count; i++)
NSLog(#"parsed %d %#", i, [csvContentArray objectAtIndex:i]);
[parser closeFile];

Can I parse a XML file that is on a web server without downloading the file?

I need to parse a XML file which is located on my server and return the node values without ever downloading the file to the device. Right now, the file is downloading to the device for testing purposes. Here is my current code:
+ (NSString *)dataFilePath:(BOOL)forSave {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *documentsPath = [documentsDirectory stringByAppendingPathComponent:#"file.xml"];
return documentsPath;
}
+ (NSString *)parse:(NSString *)nodesForPath:(NSString *)elementsForName {
NSString *filePath = [self dataFilePath:FALSE];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc == nil) { return nil; }
ViewController *view = [[[ViewController alloc] init] autorelease];
NSArray *getVersionInfo = [doc nodesForXPath:nodesForPath error:nil];
for (GDataXMLElement *versionInfo in getVersionInfo) {
NSArray *elm1 = [versionInfo elementsForName:elementsForName];
GDataXMLElement *elm2 = (GDataXMLElement *) [elm1 objectAtIndex:0];
return elm2.stringValue;
}
[doc release];
[xmlData release];
}
It works fine but it parses the file in the document's directory. How would I set it up to parse directly from the web server? Thanks
The only way I can see to do this would be to run a program on the server to parse the file and return the result to the phone.
For the phone to run the code that parses the file it has to read the file which, by definition, will download it.
You could try using a pull parser for the XML and just work with the data received from the network as a stream, discarding unneeded contents.
You read a few bytes from the response, parse them, process, discard, read some more. You might have to make your own implementation of a pull parser because your dealing with incomplete, hence invalid, XML or to look up a parser that's tolerant to data ending (definitely not a validating one).
It might be worth-while to make your own implementation for the parser if you are dealing with really huge XML files. This way you can only store pieces of the XML that you need (you might need part of the XML 'tree' or none at all or you might need to retain other nodes referenced by another node in your XML).
I'm sorry for the generic answer, but I haven't used XML parsers on iOS yet and I'm not anywhere near a Mac atm to be able to test if NSXMLParser works for you.
Edit: Related post here.
Even if you don't want to save the file to your hard disk, you must have the contents of that file loaded on your RAM.
Convert NSData* to NSString, and then NSString to char* and give that to RapidXML.

Load remote csv into CHCSVParser

I am using Dave DeLong's CHCSVParser to parse a csv. I can parse the csv locally, but I cannot get it load a remote csv file. I have been staring at my MacBook way too long today and the answer is right in front of me. Here is my code:
NSString *urlStr = [[NSString alloc] initWithFormat:#"http://www.somewhere.com/LunchSpecials.csv"];
NSURL *lunchFileURL = [NSURL URLWithString:urlStr];
NSStringEncoding encoding = 0;
CHCSVParser *p = [[CHCSVParser alloc] initWithContentsOfCSVFile:[lunchFileURL path] usedEncoding:&encoding error:nil];
[p setParserDelegate:self];
[p parse];
[p release];
Thanks for any help that someone can give me.
-[NSURL path] is not doing what you're expecting.
If I have the URL http://stackoverflow.com/questions/4636428, then it's -path is /questions/4636428. When you pass that path to CHCSVParser, it's going to try and open that path on the local system. Since that file doesn't exist, you won't be able to open it.
What you need to do (as Walter points out) is download the CSV file locally, and then open it. You can download the file in several different ways (+[NSString stringWithContentsOfURL:...], NSURLConnection, etc). Once you've got either the file saved locally to disk or the string of CSV in memory, you can then pass it to the parser.
If this is a very big file, then you'll want to alloc/init a CHCSVParser with the path to the local copy of the CSV file. The parser will then read through it bit by bit and tell you what it finds via the delegate callbacks.
If the CSV file isn't very big, then you can do:
NSString * csv = ...; //the NSString containing the contents of the CSV file
NSArray * rows = [csv CSVComponents];
That will return an NSArray of NSArrays of NSStrings.
Similar to this last approach is using the NSArray category method:
NSString * csv = ...;
NSError * error = nil;
NSArray * rows = [NSArray arrayWithContentsOfCSVString:csv encoding:[csv fastestEncoding] error:&error];
This will return the same structure (an NSArray of NSArrays of NSStrings), but it will also provide you with an NSError object if it encounters a syntax error in the CSV file (ie, malformed CSV).
I think you need an NSString, not an NSURL object to pass to the parser so the extra part you are doing with changing the NSString to an NSURL is the issue. Looking at the CHCSVParser documentation, it looks like he wants NSString in the init.
So maybe you could do something like:
NSError *err = [[[NSError alloc] init] autorelease];
NSString *lunchFileURL = [[NSString stringWithFormat:#"http://www.somewhere.com/LunchSpecials.csv"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *lunchFile = [NSString stringWithContentsOfURL:[NSURL URLWithString:lunchFileURL] encoding:NSUTF8StringEncoding error:&err];
CHCSVParser *p = [[CHCSVParser alloc] initWithContentsOfCSVString:lunchFile usedEncoding:&encoding error:nil];