Getting external XML with GDataXMLNode for Objective-C? - objective-c

I am working on a method to communicate between my PHP api and a iOS application. This is the reason why i wrote a function wich will get an external XML feed(of my api) and parse it.
But in the process to do that, i found a problem. The next code i wrote won't work:
-(void)getXML:(NSURL *)url {
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
NSURLResponse *resp = nil;
NSError *err = nil;
NSData *response = [NSURLConnection sendSynchronousRequest: theRequest returningResponse: &resp error: &err];
xmlDocument = [[GDataXMLDocument alloc]initWithData:response options:0 error:&error];
NSArray *data = [[xmlDocument rootElement]elementsForName:#"api"];
data_from_xml = [[NSMutableArray alloc]init];
for(GDataXMLElement *e in data)
{
[data_from_xml addObject:e];
}
NSLog(#"xmlDocument:%#]\n\nData:%#\n\nData_from_xml:%#\n\nURL:%#", xmlDocument,data,data_from_xml, url);
}
The log returns:
xmlDocument:GDataXMLDocument 0x5a1afb0
Data:(null)
Data_from_xml:(
)
URL:http://sr.site-project.nl/api/?t=store.search.keyword
So, it seems that GDataXMLDocument has the XML. But i can't load it with the elementsForName argument?.
Does someone see what the problem is?
The XML:
<?xml version="1.0"?>
<api><type>core.error</type><errorMessage>API store.search.keyword doesn't exists</errorMessage></api>

The api node is your root element:
NSArray *data = [[xmlDocument rootElement]elementsForName:#"api"];
Try:
NSError *error = nil;
NSArray *data = [xmlDocument nodesForXPath:#"//api" error:&error];
I personally prefer the nodesForXPath method for retrieving elements.

Related

Objective-C send get method with header to download file

in my osx app, I want to download a file from a website, in order to do that, I first tried with NSData dataWithContentsOfURL:url but I'm accessing ot throught an API, so I need to send a token in the header of my GET request so now, my method to download a file is that:
-(void)downloadFile:(NSString*)name from:(NSString*)stringURL in:(NSString*)path{
NSURL *aUrl = [NSURL URLWithString:stringURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:#"GET"];
[request addValue:self.token forHTTPHeaderField:#"Authorization"];
NSLog(#"%#", stringURL);
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if ( data )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#.torrent", path,name];
[data writeToFile:filePath atomically:YES];
}
}
The url loged is the good one. But the data variable is nil and the error one contain an NSURLErrorDomaincode with the code 1002. Referring to the doc:
Returned when a properly formed URL cannot be handled by the framework.
The most likely cause is that there is no available protocol handler for the URL.
So how can I send a GET request with custom headers and then download the file ?
There are some mistakes in your code:
documentsDirectory is not used, so the data can be wrote to nowhere.
The default HTTP method is GET so you do not need to specify it.
You should pass in the full URL: http://api.t411.io/torrents/download/4693572. And I thought you may passed in api.t411.io/torrents/download/4693572 before.
And I recommend you using the NSURLSession API that Apple brings in iOS 7 and OS X v10.9.
// in viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
_config = [NSURLSessionConfiguration defaultSessionConfiguration];
_config.HTTPAdditionalHeaders = #{#"Authorization": self.token};
_session = [NSURLSession sessionWithConfiguration:_config];
}
- (void)downloadFile:(NSString*)name from:(NSString*)stringURL in:(NSString*)path {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLSessionDataTask *task = [_session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
return;
}
if (data) {
// Your file writing code here
NSLog(#"%#", data);
}
}];
[task resume];
}

Trying to parse JSON data from Flickr. Cocoa error 3840

I’ve never used an API in conjunction with web services before and I’m having trouble parsing the JSON data I’m receiving from Flickr’s API. The only thing I do know (from all the things I have read) is that it is easy and very simple. About as far as I can get is returning a string in the console. Using a dictionary returns null and or an error. What am I missing? I want to be able to pull out the id and owner so that I can get the photo url.
This returns data on my photo:
NSString *json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#”%#”, json); //this returns data on my photo
This returns null(resultDict) and error 3840:
NSString *requestString = #”https://api.flickr.com/services/rest?&method=......etc;
NSURL *url = [NSURL URLWithString:requestString];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask *task = [session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableDictionary *resultdict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
NSLog(#”%#”, resultDict); //returns null
If (error != nil) { NSLog(#”%#”, [error localizedDescription]); }
else { self.myDict = [[resultDict objectforKey:#”photos”] objectAtIndex:0];
NSLog(#”%#”, self.myDict); }
}];
[task resume];
To check if I have an array of dictionaries I did the following and it returned 0:
NSMutableArray *resultArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainer error:&error]; error:&error];
NSLog(#"%lu", (unsigned long)resultArray.count);
Are you sure that
[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
returns a Dictionary and not an Array of Dictionnaries?
EDIT :
Can you try to use this to request the API please?
I checked in my projects, my reponses seems to have the same syntax as yours.
Only the code I use is different.
(If you could give us the full URL you've to call, it would be easier for us ^^')
NSString *str=#"YOUR URL";
NSURL *url=[NSURL URLWithString:str];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse:&response error: &error];
NSMutableDictionary* resultList = [NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableContainers error:nil];
I copied it without the errors. I let you manage that ^^
NSMutableDictionary ***resultdict** = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
NSLog(#”%#”, **resultDict**); //returns null
resultdict and resultDict are not the same variables. I bet you have an instance variable or a global variable somewhere named resultDict. Instance variables should start with an underscore, among other reasons because it avoids problems like this.
For question maker this answer won't be actual but maybe for them who will face with such problem.
I had the same problem when tried to get data from flickr.photos.getRecent method. I forgot to add into URL parametrs value nojsoncallback=1.
Without it you get response in JSONP.

Converting JSON Result as an Array

I have this JSON data :
array: {
data = (
{
"com_id" = 1;
"com_name" = Apple;
},
{
"com_id" = 2;
"com_name" = "Google";
},
{
"com_id" = 3;
"com_name" = "Yahoo";
}
);
message = "Data found";
response = success;
}
here's my code to fetch that data :
NSURL * url = [[NSURL alloc] initWithString:#"https://jsonurlhere.com"];
// Prepare the request object
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30];
// Prepare the variables for the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
// Construct a Array around the Data from the response
NSArray* object = [NSJSONSerialization
JSONObjectWithData:urlData
options:0
error:&error];
NSLog(#"array: %#", object);
now, I want to use that JSON data into my PickerView. how to change that JSON data into array so that I can load it to replace my existing array (self.nameCompany)?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.nameCompany = #[#"Apple", #"Google", #"Yahoo"];
}
I think It's helpful to you. Can you try this following link? It's not use to any supporting files. Also, see this link NSJSONSerialization supported URL
NSJSONSerialization
check this code , your response is not a array but Dictionary.
-(void)loadData{
NSURL * url = [[NSURL alloc] initWithString:#"https://jsonurlhere.com"];
// Prepare the request object
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30];
// Prepare the variables for the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
// Construct a Array around the Data from the response
NSDictionary* object = [NSJSONSerialization
JSONObjectWithData:urlData
options:0
error:&error];
NSLog(#"array: %#", [object objectForKey:#"data"]);
NSMutableArray *companyArray=[[NSMutableArray alloc] init];
for (NSDictionary *tempDict in [object objectForKey:#"data"]) {
[companyArray addObject:[tempDict objectForKey:#"com_name"]];
}
self.nameCompany=[NSArray arrayWithArray:companyArray];
}

JSON to Objective-C Dictionary

I'm making URL Request to an API but I dont know how to render the JSON, It generates an array of multiple users like this [{"user": "value"}, {"user":"value"}] and I was trying to use a TableView so I need an NSDictionary but i think is better to render a JSON like {users: [{"user": "value"}, {"user":"value"}]}. I have this code to make the request
#import "JSONKit.h"
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
users = [[jsonData objectFromJSONData] objectForKey:#"users"];
usersKeys = [users allKeys];
but I'm getting this error
2012-09-16 18:51:11.360 tableview[2979:c07] -[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180
2012-09-16 18:51:11.362 tableview[2979:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180'
I dont really know how to accomplish this so any help is useful, thanks
You are getting that error because whatever got parsed out of "jsonData" isn't necessarily what you expected (i.e. a dictionary).
Perhaps you need some error checking in that code of yours.
For example:
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(jsonData)
{
id objectReturnedFromJSON = [jsonData objectFromJSONData];
if(objectReturnedFromJSON)
{
if([objectReturnedFromJSON isKindOfClass:[NSDictonary class]])
{
NSDictionary * dictionaryFromJSON = (NSDictionary *)objectReturnedFromJSON;
// assuming you declared "users" & "usersKeys" in your interface,
// or somewhere else in this method
users = [dictionaryFromJSON objectForKey:#"users"];
if(users)
{
usersKeys = [users allKeys];
} else {
NSLog( #"no users in the json data");
}
} else {
NSLog( #"no dictionary from the data returned by the server... check the data to see if it's valid JSON");
}
} else {
NSLog( #"nothing valid returned from the server...");
}
} else {
NSLog( #"no data back from the server");
}
I was thinking on something like this
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
JSONDecoder *decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray *json = [decoder objectWithData:jsonData];
NSMutableArray *objects = [[NSMutableArray alloc] init];
NSMutableArray *keys = [[NSMutableArray alloc] init];
for (NSDictionary *user in json) {
[objects addObject:[user objectForKey:#"user" ]];
[keys addObject:[user objectForKey:#"value" ]];
}
users = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
NSLog(#"users: %#", users);
usersKeys = [users allKeys];
But it doesnt look efficient for many items or im wrong?

NSURLConnection closes early on GET

I'm working on a method to centralize my URL connections for sending and receiving JSON data from a server. It works with POST, but not GET. I'm using a Google App Engine server and on my computer it'll handle the POST requests and return proper results (and log appropriately), but I get the following error when I try the request with a GET method:
Error Domain=kCFErrorDomainCFNetwork Code=303 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)" UserInfo=0xd57e400 {NSErrorFailingURLKey=http://localhost:8080/api/login, NSErrorFailingURLStringKey=http://localhost:8080/api/login}
In addition, the GAE dev server shows a "broken pipe" error, indicating that the client closed the connection before the server was finished sending all data.
Here's the method:
/* Connects to a given URL and sends JSON data via HTTP request and returns the result of the request as a dict */
- (id) sendRequestToModule:(NSString*) module ofType:(NSString*) type function:(NSString*) func params:(NSDictionary*) params {
NSString *str_params = [NSDictionary dictionaryWithObjectsAndKeys:func, #"function", params, #"params", nil];
NSString *str_url = [NSString stringWithFormat:#"%#%#", lds_url, module];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str_url]];
NSData *data = [[NSString stringWithFormat:#"action=%#", [str_params JSONString]] dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:type];
[request setHTTPBody:data];
[request setValue:[NSString stringWithFormat:#"%d", [data length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Error: %#", error);
NSLog(#"Result: %#", [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]);
return [result objectFromJSONData];
}
A sample call would be:
NSDictionary *response = [fetcher sendRequestToModule:#"login" ofType:#"GET" function:#"validate_email" params:dict];
Again, this works with a POST but not a GET. How can I fix this?
In my case i was not calling [request setHTTPMethod: #"POST" ]
I think the root cause is you have an invalid URL.
JSON encoding will include things like '{', '}', '[' and ']'. All of these need to be URL encoded before being added to a URL.
NSString *query = [NSString stringWithFormat:#"?action=%#", [str_params JSONString]];
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", str_url, query]];
To directly answer your question:
According to CFNetwork Error Codes Reference the error is kCFErrorHTTPParseFailure. This means the client failed to correctly parse the HTTP response.
The reason why is that a GET doesn't include a body. Why would you want to submit JSON in a GET anyways?
If the target api returns data only you pass it in the url params.
If you want to send data and "get" a response use a post and examine the body on return.
Sample Post:
NSError *error;
NSString *urlString = [[NSString alloc] initWithFormat:#"http://%#:%#/XXXX/MVC Controller Method/%#",self.ServerName, self.Port, sessionId ];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
// hydrate the remote object
NSString *returnString = [rdc JSONRepresentation];
NSData *s10 = [returnString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:s10];
NSURLResponse *theResponse = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&error];
NSString *message = [[NSString alloc] initWithFormat: #"nothing"];
if (error) {
message = [[NSString alloc] initWithFormat:#"Error: %#", error];
} else {
message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
NSLog(#"%#", message);
return message;