Error in calling xml parser method - iphone

I am using retailligence barcode api and using nsxml parser method to parse the response below is the code but it didn't give call to parsing method. What's wrong there. Please help
{ NSString *myxmlstr = [NSString stringWithFormat:#"http://apitest.retailigence.com/v1.2/products?apikey=rMMzX5IDYVmTjQ3A7D9sZXukjKiZVmdD&barcode=%#&latitude=37.439097&longitude=-122.175806",brcode];
NSLog(#"my myxmlsstr is %#",myxmlstr);
dataselected = NO;
NSURL * xmlURL = [NSURL fileURLWithPath:myxmlstr];
myParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
myParser.delegate = self;
BOOL success = [myParser parse];
if(success){
NSLog(#"Properly done ");
}
else{
NSLog(#"not done");
}
}
Thanks in advance.

It was an error in code and I have to just replace this code
NSURL * xmlURL = [NSURL fileURLWithPath:myxmlstr];
with this code
NSURL * xmlURL = [NSURL URLWithString:myxmlstr];
This will work.

more information about parsing you get if you call -parserError or use method from protocol - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError to obtain error informations

Related

NSXMLParser stops parsing after encountering special character

I am reading a XML file from google weather api and parsing it using NSXMLParser. The city in question is Paris. Here is a brief xml output I get
<?xml version="1.0"?>
<xml_api_reply version="1">
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0" ><forecast_information>
<city data="Paris, Île-de-France"/>
<postal_code data="Paris"/>
<latitude_e6 data=""/>
<longitude_e6 data=""/>
...
...
Now the code I used to pares this xml is
NSString *address = #"http://www.google.com/ig/api?weather=Paris";
NSURL *URL = [NSURL URLWithString:address];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
[parser setDelegate:self];
[parser parse];
...
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
NSLog(#"XML Parser 1 ... elementName ... %#", elementName);
}
This is output that I get for the above xml
XML Parser 1 ... elementName ... xml_api_reply
XML Parser 1 ... elementName ... weather
XML Parser 1 ... elementName ... forecast_information
The problem is that it parses all the tags till it reaches "city data" since there is a non-ascii character in the name Paris, Île-de-France and then it just stops. It doesn't process tags afterwards like postal_code. latitude, longitude etc.
So my question is, is there a way I can remove all non-ascii characters from the returned URL XML string?
I know what could be happening, i just had the same problem...
Look at your foundCharacters method at your parser...
I had something like this:
if (!currentElementValue) {
currentElementValue = [[NSMutableString alloc] initWithString:string];
}
and currentElementValue just stopped getting when special chars happend.
now my working code is:
if (!currentElementValue) {
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
[currentElementValue appendString:string];
}
Remember to set currentElementValue to nil at the end of your didEndElement method
Ok. I have solved this problem. This is how I got it to work.
First I do is get the XML from the URL with special characters. Then I strip out all the special characters from the XML string. Then I convert the string to NSdata and then pass that nsdata object to my NSXMLParser. Since it has no more special characters NSXMLParser is happy.
Here's the code for anyone who may run across in future. Big thank you to everyone who contributed to this post!
NSString *address = #"http://www.google.com/ig/api?weather=Paris";
NSURL *URL = [NSURL URLWithString:address];
NSError *error;
NSString *XML = [NSString stringWithContentsOfURL:URL encoding:NSASCIIStringEncoding error:&error];
//REMOVE ALL NON-ASCII CHARACTERS
NSMutableString *asciiCharacters = [NSMutableString string];
for (NSInteger i = 32; i < 127; i++)
{
[asciiCharacters appendFormat:#"%c", i];
}
NSCharacterSet *nonAsciiCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:asciiCharacters] invertedSet];
XML = [[XML componentsSeparatedByCharactersInSet:nonAsciiCharacterSet] componentsJoinedByString:#""];
NSData *data = [XML dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];
EDIT:
NSXMLParser is a horrible tool. I have successfully used RaptureXML in all my apps. Its super easy to use and avoids all this non-sense of non-ascii characters. https://github.com/ZaBlanc/RaptureXML
The problem you're having is that Google's response uses a different encoding than the ASCII or UTF8 that you're expecting. Using the handy command line tool curl, it's easy to see that:
$ curl -I http://www.google.com/ig/api?weather=Paris
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
Content-Type: text/xml; charset=ISO-8859-1
...
If you look up ISO-8859-1, you'll find that it's also known as the Latin-1 character set. One of the built-in encoding options is NSISOLatin1StringEncoding, so do this:
NSString *XML = [NSString stringWithContentsOfURL:URL encoding:NSISOLatin1StringEncoding error:&error];
Using the correct encoding will make it possible for NSString to figure out how to interpret the characters, and you'll get back usable data. Alternately, you may be able to modify your request to specify the character encoding that you want Google to provide. That might be preferable, so that you don't have to try to match the encoding you use to a specific request.
Edit: Up to this point, my answer focusses on just getting the response as a readable string. I see that you're real question involves parsing with NSXMLParser, though. I think you have at least two options here:
Modify the XML that you receive to include the character encoding. The XML that you get back is Latin-1 encoded, but the XML tag says just: <?xml version="1.0"?>. You could modify that to look like: <?xml version="1.0" encoding="ISO-8859-1"?>. I don't know if that would solve the problem with NSXMLParser, but it might.
As suggested above, request the character set that you want from Google. Adding a Accept-Charset header to the request should do the trick, though that'll make retrieving the data a little more complicated.
Stick with ISO-8859-1, so you don't need to "remove special characters". Use a different mechanism for getting the http data.
Use an NSURLConnection, it's far more flexible in the long run and asynchronos.
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:15.0];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] init];
return YES;
} else {
// Inform the user that the connection failed.
return NO;
}
}
#pragma mark - Url connection data delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
receivedData = nil;
[self badLoad];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//inform delegate of completion
[self.delegate fetchedData:receivedData];
receivedData = nil;
}

How to parse multiple xml file in iPhone using NSxml parser

I have nearly 15 and more xml file inside of one folder if possible to parse all file one by one? I set path like this below if I want to parse multiple files. how can I set path of that folder file?
this code for single file xml parser it's working fine.
NSString *playlistfilePath = [[NSBundle mainBundle] pathForResource:#"CT8OkzhF8qmEYGe2" ofType:#"xml"];
NSData *playlistfileData = [NSData dataWithContentsOfFile:playlistfilePath];
NSString *playlistxmlFile = [[NSString alloc] initWithData:playlistfileData encoding:NSASCIIStringEncoding];
//parsing the XML
PlaylistXmlParser *playlistparser = [[PlaylistXmlParser alloc] init];
[playlistparser parseXMLFile:playlistxmlFile];
that all the XML files are having same structure and same element.
On the basis of the NSXMLParser object write the logic of the parsing:-
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
//check with switch or if else condition which NSXMLParser object is using this delegate.
}
As like above all the delegates of NSXMLParser have a parameter as an NSXMLParser object.
try this:
NSXMLParser *xmlParser = [[[NSXMLParser alloc] initWithData:playlistfileData]autorelease];
PlaylistXmlParser *parser = [[PlaylistXmlParser alloc] initXMLParser:#"xmlname"];
[xmlParser setDelegate:parser];
in PlaylistXmlParser.m file
- (PlaylistXmlParser *) initXMLParser:(NSString *)name {
[super init];
xmlname =name;
return self;
}
now in every methods in PlaylistXmlParser.m file :
if ([xmlname isEqualToString:#"xmlname"]) {
//store data
}
else if([xmlname isEqualToString:#"xmlname_1"]){
//store data
}
#moorthy use pathForResourcesType:inDirectory on NSBundle method to get array of paths, Then for every single path inside the array create an instance for the parser class and parse the file.
[[NSBundle mainbundle]pathForResourcesType:#"xml" inDirectory:"Your directory Path"]
This will return an array ...... Hope it helps you

Solution for a leak in touchXML when no internet and using initWithContentsOfURL

There's a leaking CXMLDocument object shown in instruments everytime, a request to an XML is made to a webservice AND when there's no internet connection available. Here's my code:
NSString *path = ... some URL
NSURL *url = [NSURL URLWithString: path];
CXMLDocument *itemListParser; = [[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil];
... other stuff ...
If we digg deeper and trace initWithContentsOfURL call then we will find this method in "CXMLDocument.m":
- (id)initWithContentsOfURL:(NSURL *)inURL encoding:(NSStringEncoding)encoding options:(NSUInteger)inOptions error:(NSError **)outError
{
if (outError)
*outError = NULL;
NSData *theData = [NSData dataWithContentsOfURL:inURL options:NSUncachedRead error:outError];
if (theData)
{
self = [self initWithData:theData encoding:encoding options:inOptions error:outError];
}
else
{
[self release]; //My suggested fix: We need to release an alloc'ed object because after the "self = null" it will be unable to release it. See the info below.
self = NULL;
}
return(self);
}
It appears, if theData is nil (for example no connection) then self will be nil, and so the result of the call to TouchXML initWithContentsOfURL will be nil too. So, in my code:
CXMLDocument *itemListParser; = [[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil];
I'm alloc'ing a memory but init returns nil, and so itemListParser becomes nil too. So later, trying to release the parser with [itemListParser release] does nothing because release is send to nil.
I was able to fix a leak by adding "[self release]" before "self = NULL" (see the line with my comment in TouchXML initWithContentsOfURL method)

NSURL with Curly Braces

NSURL does not support the use of curly braces (i.e. {}) in URLs. My application needs to talk to a server that requires the use of curly braces in the URL. I'm considering using bridges to write the networking code in Python or C++, or even rewriting the C code for NSURL to make it accept curly braces. Percent escapes are not accepted by my remote server.
Do I have any other good alternatives?
EDIT: Explained why addingPercentEscapesUsingEncoding and the like don't work for me here.
Will it work for you if you escape the braces?
This code:
// escape {} with %7B and %7D
NSURL *url = [NSURL URLWithString:#"http://somesite.com/%7B7B643FB915-845C-4A76-A071-677D62157FE07D%7D.htm"];
NSLog(#"%#", url);
// {} don't work and return null
NSURL *badurl = [NSURL URLWithString:#"http://somesite.com/{7B643FB915-845C-4A76-A071-677D62157FE07D}.htm"];
NSLog(#"%#", badurl);
Outputs:
2011-11-30 21:25:06.655 Craplet[48922:707] http://somesite.com/%7B7B643FB915-845C-4A76-A071-677D62157FE07D%7D.htm
2011-11-30 21:25:06.665 Craplet[48922:707] (null)
So, escaping seems to work
Here's how you can programmatically escape the url:
NSString *escapedUrlString = [unescaped stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
EDIT:
In your comment below, you said your server won't accept encoded braces and was there any other alternatives. First, I would try and get the server fixed. If that's not possible ... I haven't tried this with braces etc... but the layer below NS networking classes is CFNetworking.
See this:
http://developer.apple.com/library/ios/#documentation/Networking/Conceptual/CFNetwork/CFHTTPTasks/CFHTTPTasks.html#//apple_ref/doc/uid/TP30001132-CH5-SW2
From that doc:
CFStringRef url = CFSTR("http://www.apple.com");
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
CFStringRef requestMethod = CFSTR("GET");
....
Once again, haven't tried it and I'm running out. might try it later but if a layer isn't working your first options are to move down the stack.
Bryan's answer is perfectly great (+1 to him!), but another solution would be to use NSString's stringByAddingPercentEscapesUsingEncoding: method.
Like this:
NSString * originalURLAsString = [NSString stringWithString: #"http://somesite.com/{7B643FB915-845C-4A76-A071-677D62157FE07D}.htm"];
NSString * properlyEncodedString = [originalURLAsString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
NSURL * url = [NSURL URLWithString: properlyEncodedString];
I hope this info helps you out!
To call using CFNetwork can use the follwoing
-(void)getDataFromUrl{
CFStringRef tempURLA = CFSTR("http://my.test.server/iostest/index.html?{\"a\":\"b\"}");
CFStringRef tempUrlSting = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)tempURLA,CFSTR("{}"), CFSTR("\""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, tempUrlSting, NULL);
CFStringRef requestMethod = CFSTR("GET");
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL,kCFHTTPVersion1_1);
CFStringRef headerFieldName = CFSTR("Accept");
CFStringRef headerFieldValue = CFSTR("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
[self performHTTPRequest:myRequest];
}
-(void)performHTTPRequest:(CFHTTPMessageRef)request {
CFURLRef gotdatab = (__bridge CFURLRef)(CFBridgingRelease(CFHTTPMessageCopyRequestURL(request)));
// NSLog(#"(CFHTTPMessageRef request %#",gotdatab);
CFReadStreamRef requestStream = CFReadStreamCreateForHTTPRequest(NULL, request);
CFReadStreamOpen(requestStream);
NSMutableData *responseBytes = [NSMutableData data];
NSError *error;
while (TRUE) {
if (CFReadStreamHasBytesAvailable(requestStream)) {
UInt8 streambuffer[1024];
int readBytes = CFReadStreamRead (requestStream,streambuffer,sizeof(streambuffer));
NSLog(#"Read: %d",readBytes);
[responseBytes appendBytes:streambuffer length:readBytes];
}
if (CFReadStreamGetStatus(requestStream) == kCFStreamStatusError) {
error = (NSError*)CFBridgingRelease(CFReadStreamCopyError (requestStream));
if ([error code] == 61) {
// connection refused
NSLog(#"Error occured: %d",[error code]);
}
break;
}
if (CFReadStreamGetStatus(requestStream) == kCFStreamStatusAtEnd) {
NSLog(#"Stream reached end!");
error = nil;
break;
}
}//
CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(requestStream, kCFStreamPropertyHTTPResponseHeader);
if (response==NULL) {
NSLog(#"response is null");
return;
}
}
The above was done using examples from here and here
But even the above method has the same issue. That is: if {} are not encoded the URL doesn't get generated. If the {} are encoded the server doesn't return a proper value.
Any other suggestions to resolve this posts issue?

Need help with NSXMLPaser tutorial

At the last part of the tutorial I am having an issue with the users variable, its saying users variable is undeclared.
It is being declared in my NSXMLPaser class that I created as a NSMutableArray and I am "#import"ing the header file of NSXMLPaser class...
Here is the link to the tutorial I am working through, any help would be greatly appreciated.
http://wiki.cs.unh.edu/wiki/index.php/Parsing_XML_data_with_NSXMLParser
- (void) doParse:(NSData *)data {
NSString * filePath = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"xml"];
NSData * fileData = [NSData dataWithContentsOfFile:filePath];
// create and init NSXMLParser object
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:fileData];
// create and init our delegate
XMLParser *parser = [[XMLParser alloc] initXMLParser];
// set delegate
[nsXmlParser setDelegate:parser];
// parsing...
BOOL success = [nsXmlParser parse];
// test the result
if (success) {
NSLog(#"No errors - user count : %i", [parser [users count]]); // users undeclared error here
// get array of users here
// NSMutableArray *users = [parser users];
} else {
NSLog(#"Error parsing document!");
}
[parser release];
[nsXmlParser release];
}
Either you use "[parser.users count]" like Babji said or you could use the dot notation for everything, like "parser.users.count".
Also, you could use "[[parser users] count]". This means you first get the collection users of the parser ("[parser users]") and then you call count on that collection ("[[parser users] count]").
use the users variable [parser.user count]