Parse JSON file into POST request Objective C - objective-c

I parse an JSON File into an Dictionary and in a further step I want to build a post request for couchDB.
The parsing works fine, but if I post I get an error. I thinks it has something to do with my escape sequence in the post string.
Here´s the code:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"json"];
NSString *fileContent = [[NSString alloc] initWithContentsOfFile:filePath];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *data = (NSDictionary *) [parser objectWithString:fileContent error:nil];
// getting the data from file
NSString *_id = (NSString *) [data objectForKey:#"_id"];
NSString *rev_ = self.rev;
NSString *_herausgeber = (NSString *) [data objectForKey:#"Herausgeber"];
NSString *_nummer = (NSString *) [data objectForKey:#"Nummer"];
NSNumber *_deckung = [data objectForKey:#"Deckung"];
NSString *_waerhung = (NSString *) [data valueForKey:#"Waehrung"];
NSDictionary *_inhaber = (NSDictionary *) [data objectForKey:#"Inhaber"];
NSString *_name = (NSString *) [_inhaber objectForKey:#"Name"];
NSString *_vorname = (NSString *) [_inhaber objectForKey:#"Vorname"];
NSNumber *_maennlich = (NSNumber *) [_inhaber objectForKey:#"maennlich"];
NSArray *_hobbys = (NSArray *) [_inhaber objectForKey:#"Hobbys"];
NSString *_hobby0 = [_hobbys objectAtIndex:0];
NSString *_hobby1 = [_hobbys objectAtIndex:1];
NSString *_hobby2 = [_hobbys objectAtIndex:2];
NSNumber *_alter = (NSNumber *) [_inhaber objectForKey:#"Alter"];
NSArray * _kinder = (NSArray *) [_inhaber objectForKey:#"Kinder"];
NSString *_kind0 = [_kinder objectAtIndex:0];
NSString *_kind1 = [_kinder objectAtIndex:1];
NSString *_kind2 = [_kinder objectAtIndex:2];
NSString *_partner = (NSString *) [_inhaber objectForKey:#"Partner"];
[parser release];
//post string:
NSString *post = [NSString stringWithFormat:#"{\"_id\":\"%#\",\"_rev\":\"%#\",\"Herausgeber\":\"%#\",\"Nummer\":\"%#\",\"Deckung\":%#,\"Waehrung\":\"%#\",\"Inhaber\":{\"Name\":\"%#\",\"Vorname\":\"%#\",\"maennlich\":%#,\"Hobbys\":[\"%#\",\"%#\",\"%#\"],\"Alter\":%#,\"Kinder\":[\"%#\",\"%#\",\"%#\"],\"Partner\":%#}}",_id,rev_,_herausgeber,_nummer,_deckung,_waerhung,_name,_vorname,_maennlich,_hobby0,_hobby1,_hobby2,_alter,_kind0,_kind1,_kind2,_partner];
//post header:
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:cdbURL]];
[request setHTTPMethod:#"PUT"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
The Error I get:
Reply: {"error":"bad_request","reason":"invalid UTF-8 JSON:
<<\"{\\"_id\\":\\"161eba7093799b610502bdfba5004281\\",\\"_rev\\":\\"199-bb065cbd0a365b188fc492cc22453d74\\",\\"Herausgeber\\":\\"SAP\\",\\"Nummer\\":\\"1234-5678-9012-3456\\",\\"Deckung\\":2000000,\\"Waehrung\\":\\"Franc\\",\\"Inhaber\\":{\\"Name\\":\\"Mustermann\\",\\"Vorname\\":\\"Max\\",\\"maennlich\\":1,\\"Hobbys\\":[\\"Reiten\\",\\"Golfen\\",\\"Lesen\\"],\\"Alter\\":42,\\"Kinder\\":[\\"Max\\",\\"Moritz\\",\\"Lisa\\"],\\"Partner\\":}}\">>"}
How can I solve this problem?

Personally, I would avoid constructing the JSON post-string myself and instead use SBJson's [NSObject JSONRepresentation] function.
Then you could fill an NSDictionary and have the API construct the JSON for you.
NSString *_id = #"161";
NSString *_rev = #"199";
NSString *_herausgeber = #"SAP";
NSMutableDictionary *toPost = [NSMutableDictionary dictionary];
[toPost setObject:_id forKey:#"_id"];
[toPost setObject:_rev forKey:#"_rev"];
[toPost setObject:_herausgeber forKey:#"Herausgeber"];
NSLog(#"JSON: %#", [toPost JSONRepresentation]);
Gives:
JSON: {"_id":"161","_rev":"199","Herausgeber":"SAP"}

Related

how to submit a password with special characters from app to a web-server by NSURLConnection

I have to login with my to a web-server.All works fine, but not generated passwords like |%<">{}¥^~ . How I have to encode passwords like this?
I create a User with password=|%<">{}¥^~
doset work
( for example a password like "user1234" works fine)
NSString *userName = self.usernameOutlet.text;
NSString *userPassword = self.passwordOutlet.text;
NSString *escapedString = [self.passwordOutlet.text stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
userPassword = escapedString;
NSString *post = [NSString stringWithFormat:#"login=%#&password=%#",userName,userPassword];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://XXXXXXXX/login"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
with passwords like "user1234" I get a cookie
with passwords like "|%<">{}¥^~" I get no cookie
what am I doing wrong?
It’s tempting to want to use URLQueryAllowedCharacterSet, but that won’t work for all strings. Notably & and + will pass unescaped.
If you’re wondering why we must percent escape & and +, too, it’s because these two characters have a special meaning in x-www-form-urlencoded requests. The & is used to delimit key-value pairs in a x-www-form-urlencoded request, so it will truncate your password. And most web services translate a + to a space, so you’ll want to percent escape that, too.
So, let’s first define a character set that will work:
// NSCharacterSet+URLQueryValueAllowed.h
#interface NSCharacterSet (URLQueryValueAllowed)
#property (class, readonly, copy) NSCharacterSet *URLQueryValueAllowedCharacterSet;
#end
and
// NSCharacterSet+URLQueryValueAllowed.m
#implementation NSCharacterSet (URLQueryValueAllowed)
+ (NSCharacterSet *)URLQueryValueAllowedCharacterSet {
static dispatch_once_t onceToken;
static NSCharacterSet *queryValueAllowed;
dispatch_once(&onceToken, ^{
NSMutableCharacterSet *allowed = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
NSString *generalDelimitersToEncode = #":#[]#"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
NSString *subDelimitersToEncode = #"!$&'()*+,;=";
[allowed removeCharactersInString:generalDelimitersToEncode];
[allowed removeCharactersInString:subDelimitersToEncode];
queryValueAllowed = [allowed copy];
});
return queryValueAllowed;
}
#end
Then, to make life easier for us, let’s define NSDictionary category for percent encoding a dictionary:
// NSDictionary+PercentEncoded.h
#interface NSDictionary (PercentEncoded)
- (NSString *)percentEncodedString;
- (NSData *)percentEncodedData;
#end
and
// NSDictionary+PercentEncoded.m
#implementation NSDictionary (PercentEncoded)
- (NSString *)percentEncodedString {
NSMutableArray<NSString *> *results = [NSMutableArray array];
NSCharacterSet *allowed = [NSCharacterSet URLQueryValueAllowedCharacterSet];
for (NSString *key in self.allKeys) {
NSString *encodedKey = [key stringByAddingPercentEncodingWithAllowedCharacters:allowed];
NSString *value = [[self objectForKey:key] description];
NSString *encodedValue = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed];
[results addObject:[NSString stringWithFormat:#"%#=%#", encodedKey, encodedValue]];
}
return [results componentsJoinedByString:#"&"];
}
- (NSData *)percentEncodedData {
return [[self percentEncodedString] dataUsingEncoding:NSUTF8StringEncoding];
}
#end
Then, your application code can do:
NSDictionary *dictionary = #{#"login": userName, #"password": userPassword};
NSData *body = [dictionary percentEncodedData];

FatSecret API "invalid signature"

Using this repository I was not able to make the queries work when oauth_token must be provided. I always get invalid signature. Tried a lot of solutions and tweaks in the code, nothing worked. Please help.
This is the code from the git mentioned:
NSString *OAuthorizationHeader(NSURL *url, NSString *method, NSData *body, NSString *_oAuthConsumerKey, NSString *_oAuthConsumerSecret, NSString *_oAuthToken, NSString *_oAuthTokenSecret)
{
NSString *_oAuthNonce = [NSString ab_GUID];
NSString *_oAuthTimestamp = [NSString stringWithFormat:#"%d", (int)[[NSDate date] timeIntervalSince1970]];
NSString *_oAuthSignatureMethod = #"HMAC-SHA1";
NSString *_oAuthVersion = #"1.0";
NSMutableDictionary *oAuthAuthorizationParameters = [NSMutableDictionary dictionary];
[oAuthAuthorizationParameters setObject:_oAuthNonce forKey:#"oauth_nonce"];
[oAuthAuthorizationParameters setObject:_oAuthTimestamp forKey:#"oauth_timestamp"];
[oAuthAuthorizationParameters setObject:_oAuthSignatureMethod forKey:#"oauth_signature_method"];
[oAuthAuthorizationParameters setObject:_oAuthVersion forKey:#"oauth_version"];
[oAuthAuthorizationParameters setObject:_oAuthConsumerKey forKey:#"oauth_consumer_key"];
if(_oAuthToken)
[oAuthAuthorizationParameters setObject:_oAuthToken forKey:#"oauth_token"];
// get query and body parameters
NSDictionary *additionalQueryParameters = [NSURL ab_parseURLQueryString:[url query]];
NSDictionary *additionalBodyParameters = nil;
if(body) {
NSString *string = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
if(string) {
additionalBodyParameters = [NSURL ab_parseURLQueryString:string];
}
}
// combine all parameters
NSMutableDictionary *parameters = [oAuthAuthorizationParameters mutableCopy];
if(additionalQueryParameters) [parameters addEntriesFromDictionary:additionalQueryParameters];
if(additionalBodyParameters) [parameters addEntriesFromDictionary:additionalBodyParameters];
// -> UTF-8 -> RFC3986
NSMutableDictionary *encodedParameters = [NSMutableDictionary dictionary];
for(NSString *key in parameters) {
NSString *value = [parameters objectForKey:key];
[encodedParameters setObject:[value ab_RFC3986EncodedString] forKey:[key ab_RFC3986EncodedString]];
}
NSArray *sortedKeys = [[encodedParameters allKeys] sortedArrayUsingFunction:SortParameter context:(__bridge void *)(encodedParameters)];
NSMutableArray *parameterArray = [NSMutableArray array];
for(NSString *key in sortedKeys) {
[parameterArray addObject:[NSString stringWithFormat:#"%#=%#", key, [encodedParameters objectForKey:key]]];
}
NSString *normalizedParameterString = [parameterArray componentsJoinedByString:#"&"];
NSLog(#"normalizedParameters: %#", normalizedParameterString);
NSString *normalizedURLString;
if ([url port] == nil) {
normalizedURLString = [NSString stringWithFormat:#"%#://%#%#", [url scheme], [url host], [url path]];
} else {
normalizedURLString = [NSString stringWithFormat:#"%#://%#:%#%#", [url scheme], [url host], [url port], [url path]];
}
NSString *signatureBaseString = [NSString stringWithFormat:#"%#&%#&%#",
[method ab_RFC3986EncodedString],
[normalizedURLString ab_RFC3986EncodedString],
[normalizedParameterString ab_RFC3986EncodedString]];
NSLog(#"signature base: %#", signatureBaseString);
NSString *key = [NSString stringWithFormat:#"%#&%#&",
[_oAuthConsumerSecret ab_RFC3986EncodedString],
[_oAuthTokenSecret ab_RFC3986EncodedString]];
NSLog(#"key codes: %#", key);
NSData *signature = HMAC_SHA1(signatureBaseString, key);
NSString *base64Signature = [signature base64EncodedString];
// PARKER CHANGE: changed oAuthAuthorizationParameters to parameters
NSMutableDictionary *authorizationHeaderDictionary = [parameters mutableCopy];
[authorizationHeaderDictionary setObject:base64Signature forKey:#"oauth_signature"];
NSMutableArray *authorizationHeaderItems = [NSMutableArray array];
for(NSString *key in authorizationHeaderDictionary) {
NSString *value = [authorizationHeaderDictionary objectForKey:key];
NSLog(#"KEY: %#", key);
NSLog(#"VALUE: %#", value);
// PARKER CHANGE: removed quotes that surrounded each value
[authorizationHeaderItems addObject:[NSString stringWithFormat:#"%#=%#",
[key ab_RFC3986EncodedString],
[value ab_RFC3986EncodedString]]];
}
// PARKER CHANGE: changed concatentation string from ", " to "&"
NSString *authorizationHeaderString = [authorizationHeaderItems componentsJoinedByString:#"&"];
// authorizationHeaderString = [NSString stringWithFormat:#"OAuth %#", authorizationHeaderString];
NSLog(#"final: %#", authorizationHeaderString);
return authorizationHeaderString;
}
And this is how I'm calling it:
- (void) makeUserRequestWithMethod:(NSString *)method
parameters:(NSDictionary *)params
completion:(void (^)(NSDictionary *data))completionBlock {
NSLog(#"%s", __func__);
NSMutableDictionary *parameters = [params mutableCopy];
[parameters addEntriesFromDictionary:[self defaultParameters]];
[parameters addEntriesFromDictionary:#{ #"method" : method }];
NSString *queryString = [self queryStringFromDictionary:parameters];
NSData *data = [NSData dataWithBytes:[queryString UTF8String] length:queryString.length];
NSString *authHeader = OAuthorizationHeader([NSURL URLWithString:FAT_SECRET_API_ENDPOINT],
#"POST",
data,
_oauthConsumerKey,
_oauthConsumerSecret,
_oAuthToken,
_oAuthTokenSecret
);
NSLog(#"header: %#", authHeader);
NSURL *url = [NSURL URLWithString:[FAT_SECRET_API_ENDPOINT stringByAppendingFormat:#"?%#", authHeader]];
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
id JSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
completionBlock(JSON);
} else {
completionBlock(nil);
}
}] resume];
}
I'm going to go out on a limb here and say that the code that others have proven to work is probably not at fault here, but rather first look at your own code. You say the error messages is "Invalid Signature" which sounds like it's a warning from the server you're calling, not from the code you're using.
[parameters addEntriesFromDictionary:[self defaultParameters]];
[parameters addEntriesFromDictionary:#{ #"method" : method }];
NSString *queryString = [self queryStringFromDictionary:parameters];
What happens inside [self defaultParameters] and are you 100% certain the parameters are appropriate (including spelling) for the API you're calling?
Have you verified that [self queryStringFromDictionary:parameters] prepares a properly formatting query string, and isn't introducing some error (non-escaped special characters, or percent encoding, for example)?

Multidimention array with objectAtIndex

I try to read a multidimensional array as request from content:
[
{
"content" : {
"parcel" : {
"ServiceParcelEventPostalCode" : "1005",
"ConsigneePostalCode" : "1220 (292)",
"ParcelTypeDescription" : "Paket",
"ReferenceIdentcode" : "1017348010239480212208",
"CustomerShipmentNr" : "N\/A",
"Identcode" : "1017348010239480212208",
"ReferenceNumber" : "D1Lmp8TPN_1",
.......... etc
I'm, trying to get ServiceParcelEventPostalCode without access :
NSString *urlString = #"http://www.post.at/sendungsverfolgung4.php";
NSURL *url = [NSURL URLWithString:urlString];
// URL-Request-Objekt erstellen
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"GET"];
NSMutableData *body = [NSMutableData data];
NSString *postWerte = [NSString stringWithFormat:#"id=%#", self.textfeld.text];
[body appendData:[postWerte dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
// Abfrage ans Web senden und Rückgabe in Variable speichern
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
const char *convert = [returnString UTF8String];
NSString *responseString = [NSString stringWithUTF8String:convert];
NSMutableArray *meinErgebnis = [responseString JSONValue];
NSString *wert1 = [NSString stringWithFormat:#"%#",[[[meinErgebnis objectAtIndex:2] objectAtIndex:0] objectForKey:#"ServiceParcelEventPostalCode"]];
Just follow structure of your JSON. [] in JSON means array, {} means dictionary. If JSON in your example is your responseString:
NSMutableArray *jsonArray = [responseString JSONValue];
NSString *postalCode = nil;
if (jsonArray.count)
{
NSDictionary *elementDict = [jsonArray objectAtIndex:0];
NSDictionary *contentDict = [elementDict objectForKey:#"content"];
NSDictionary *parcelDict = [contentDict objectForKey:#"parcel"];
postalCode = [parcelDict objectForKey:#"ServiceParcelEventPostalCode"];
}

Parsing a JSON text

With the following way...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"/lkj/"]];
NSString *fileName = [NSString stringWithFormat:#"/sandbox/2012_05_11.json"];
[[self restClient] loadFile:fileName intoPath:path];
NSString *fileContent = [[NSString alloc] initWithContentsOfFile:path];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *data = (NSDictionary *) [parser objectWithString:fileContent error:nil];
// getting the data from inside of "menu"
NSString *message = (NSString *) [data objectForKey:#"message"];
NSString *name = (NSString *) [data objectForKey:#"name"];
namegroup.text = [NSString stringWithFormat:#"%# %#",name, message];
...I am trying to parse a document I have previously made with other code...
{"message":["Untitled1a","Untitled2a","Untitled3a"],"name":["Untitled1b","Untitled2b","Untitled3b"]}
with the code above though, in name group.text, this appears...
(untitled, untitled, untitled) (untitled, untitled, untitled)
...but what I would like to do is to allocate many UITextFields, each of them in pairs, (2, 2, 2..), one field which displays the name and the other the message, so pair up 1a with 1b, 2a with 2b... obviously the fields won't be Untitled1a, but "how are you"...
But I can't seem to fix this issue!! Please help!!
You may try something like this:
NSArray *message = [data objectForKey:#"message"];
NSArray *name = [data objectForKey:#"name"];
NSDictionary* Dictionary = [NSDictionary dictionaryWithObjects:message forKeys:name];
for (NSString* Key in [Dictionary allKeys]){
NSLog(#"%# %#",Key,[Dictionary objectForKey:Key]);
}

How to Parse JSON Data and display in it in an iPhone Applicaiton

I want to parse the following given all the data in and array then use in iPhone application to display.
http://www.krsconnect.no/community/api.html?method=fullEvents&appid=620
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.krsconnect.no/community/api.html?method=fullEvents&appid=620"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *object = [parser objectWithString:json_string error:nil];
NSArray *results = [parser objectWithString:json_string error:nil];
NSDictionary *dictOne = [results objectAtIndex:0];
NSArray *activitiesArray = [dictOne objectForKey:#"activities"];
NSDictionary *dictTwo = [activitiesArray objectAtIndex:0];
NSDictionary *eventDict = [dictTwo objectForKey:#"event"];
NSDictionary *dictThree = [activitiesArray objectAtIndex:0];
NSDictionary *eventDict3 = [dictThree objectForKey:#"images"];
NSLog(#"%# - %#", [eventDict3 objectForKey:#"large"]);
NSLog(#"%# - %#", [eventDict objectForKey:#"category"]);
NSLog(#"%# - %#", [eventDict objectForKey:#"content"]);
It's working fine but if I print HoursFrom from dates object it's not printing
That'll be because in your data feed, it's hoursFrom, not HoursFrom. The case is significant.