Outputting a string from NSXMLParser - ios

I'm new to Objective C and I am using a helper that returns an XML payload from a web service as an NSXMLParser. I need to get that payload as either an NSString of XML or as an NSData object so that I can use it in another library that converts the payload to an NSDictionary.
Is there an easy way to convert this XML to a string? From the docs, I see that I could write my own string builder using the events of NSXMLParser but this feels like re-inventing the wheel compared to working with XML in other languages.

Will this work for you?
NSString *googleString = #"http://www.google.com";
NSURL *googleURL = [NSURL URLWithString:googleString];
NSError *error;
NSString *googlePage = [NSString stringWithContentsOfURL:googleURL
encoding:NSASCIIStringEncoding
error:&error];
from here
Reading HTML content from a UIWebView
From here you should be able to covert to NSXmlParser or NSData but if you make this request to the service it should return the xml as string.

You can convert the NSMutableData to a string:
You send the request:
conexion = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (conexion) {
webData = [NSMutableData data];
}
Then you parse the webData to string. In this function: connectionDidFinishLoading
NSString *XML = [[NSString alloc]
initWithBytes: [webData mutableBytes]
length:[webData length]
encoding:NSUTF8StringEncoding];
If you need to display the result
NSLog(#"%#", XML);

Related

Error Domain=NSURLErrorDomain Code=-1000 "bad URL"

Following problem:
I get every time the error -1000, but really don't know what I can change. I've tried it with GET and another sending method. But I get every time the same error.
Does someone see my mistake?
thanks
NSString *get =[[NSString alloc] initWithFormat:#"mobileNumber=%#&deviceToken=%#",myMobileNumber,myDeviceToken];
[get stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"http://myHomepage.net/login.php?%#",get]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *responseData = #"";
if ([response statusCode] ==200 )
{
responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"---------responseData: %#",responseData);
return responseData;
} else {
You're not saving the result of stringByAddingPercentEscapesUsingEncoding. So, instead of:
[get stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
You need:
get = [get stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
FYI, while the above fix will now successfully percent escape all characters not permitted within in a URL, there are actually some characters that are acceptable in a URL, but are not acceptable within a parameter value (e.g. a + which is interpreted as a space, or & which delineates parameters).
It is important to percent escape the values used in the parameters of the request in such a way that you escape not only those characters that are not legal in a URL, but also a few that are otherwise legal in a URL, but are not permitted within a parameter value.
Unfortunately the standard stringByAddingPercentEscapesUsingEncoding method does not do this. But the CFURL function CFURLCreateStringByAddingPercentEscapes does. You apply this function to the individual parameter values. Here is a method that performs the necessary toll-free bridging between this function and ARC:
- (NSString *)percentEscapeString:(NSString *)string
{
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
(CFStringRef)#" ",
(CFStringRef)#":/?#!$&'()*+,;=",
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:#" " withString:#"+"];
}
You can use this method as follows:
NSString *get =[[NSString alloc] initWithFormat:#"mobileNumber=%#&deviceToken=%#", [self percentEscapeString:myMobileNumber], [self percentEscapeString:myDeviceToken]];
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"http://myHomepage.net/login.php?%#",get]];
This should correctly percent escape the parameter values of the string, regardless of the presence of these reserved characters, or not.

NSXMLParser with encoded Data in String

I want to program a NSXMLParser and I have the data for this lying in a NSString (encoded).
If I put the NSString to NSLog it gives me the right lines I need. But when I want to start the Parser with the data from that NSString it doesn't start.
Here is my code:
The interface:
#interface StundenplanParser () <NSXMLParserDelegate>
#end
The method that gets called from the ViewController:
-(void)parserStart
{
// Create your request string with parameter name as defined in PHP file
NSString *myRequestString = [NSString stringWithFormat:#"matr=%#&pressme=%#",#"33886",#"S T A R T"];
// Create Data from request
NSData *myRequestData = [NSData dataWithBytes: [myRequestString UTF8String] length: [myRequestString length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://www2.htw-dresden.de/~rawa/cgi-bin/auf/raiplan_app.php"]];
// set Request Type
[request setHTTPMethod: #"POST"];
// Set content-type
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
// Set Request Body
[request setHTTPBody: myRequestData];
// Now send a request and get Response
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse: nil error: nil];
// Log Response
NSString *response = [[NSString alloc] initWithBytes:[returnData bytes] length:[returnData length] encoding:NSASCIIStringEncoding];
NSLog(#"Response:%#\n",[response substringToIndex:64]);
// If I would use NSASCIIStringEncoding in the following line, the data would be nil
NSData *data = [response dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
if (!parser) NSLog(#"Error with parser");
else NSLog(#"parser successfully initialised");
[parser setDelegate:self];
[parser parse];
}
NOTE: In my response (NSString*) is the code that I want to parse. If I print it out using NSLog I see the source code of the website..
Now I want to show only the elements the NSXMLParser found with this:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"found element: %#", elementName);
}
I hope it's not a problem that I left the url in the code. I just want to parse the schedule from my university.
I hope you understand what I mean and you could help me.
EDIT: My Problem is not that I don't get the XML. My Problem is that the parser won't start.. I edited the code.
EDIT2: The output from the response is:
2013-11-18 23:52:16.008 University[17210:70b] Response:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN
So it seems like it worked, but the problem is the encoding of this into a NSData instance that I need to initialize my parser.
EDIT3:
After implementing the parser:parseErrorOccurred I got the following error in the Console:
2013-11-19 08:58:26.190 University[17458:70b] ERROR while parsing: The operation couldn’t be completed. (NSXMLParserErrorDomain error 65.)
Translating with Google, the website
http://www2.htw-dresden.de/~rawa/cgi-bin/auf/raiplan_app.php
says 'Create a schedule in csv format' and entering the matriculation number from your code 33886, it returns a web page that has in its the data you're trying to get at:
<Stunde>
<titel>Englisch C1 III/SI (w.o.)</titel>
<kuerzel>Engl_C1 Üw3/SI Technik</kuerzel>
<raum>S 334</raum>
<dozent>Kilian</dozent>
<datum>16.10.2013</datum>
<anfang>7:30</anfang>
<ende>9:00</ende>
</Stunde>
If you extract this data and form a new XML string, then the XML Parser will run. The tag is where this data begins, and the last one is followed by a , so this code will extract out the elements:
NSRange startRange = [dataString rangeOfString:#"<Stunde>"];
NSString *dataAfterHtml = [dataString substringFromIndex:startRange.location];
NSRange endRange = [dataAfterHtml rangeOfString:#"<br>"];
dataAfterHtml = [dataAfterHtml substringToIndex:endRange.location];
NSString *formattedXML = [NSString
stringWithFormat:#"<data>%#</data>",
dataAfterHtml];
now give this the parser
NSData *data = [formattedXML dataUsingEncoding:NSUTF8StringEncoding];
xmlParser = [[NSXMLParser alloc] initWithData:data];
You are interpreting the data as ASCII and then encoding it as UTF8, you are going to end up with an invalid string or with a string with invalid characters. Try this:
...
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse: nil error: nil];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:returnData];
[parser setDelegate:self];
[parser parse];
You problem is that you are not URLEncoding the data, but feeding it draw into the HTTP body. In this:
NSMutableData *body = [NSMutableData data];
NSString *postWerte = #"matr=XXXXX&lang=1&aktkw=1&pressme=S T A R T";
[body appendData:[postWerte dataUsingEncoding:NSUTF8StringEncoding]];
you need to URLEncode "S T A R T", and should bee really URLencoding every string that follows an equal sign. (UPDATE: so it works as is - my service is way picker and I must encode. YMMV!)
EDIT:
So try changing your code a bit, and if it still fails then please post the first line or two of the returned data:
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse: nil error: nil];
assert(returnData); // you should be suppling an error pointer just in case but this will do for now
// Log Response
{
NSString *response = [[NSString alloc] initWithBytes:[returnData bytes] length:[returnData length] encoding:NSASCIIStringEncoding];
NSLog(#"%#",[response substringToIndex:64]); // or a bit mor
}
NSXMLParser *parser = [[NSXMLParser alloc] initWithData: returnData];
assert(parser); // will be nil if anything has gone wrong, obviously in your real code put an if test
[parser setDelegate:self]; // no affect for nil object
[parser parse];// no affect for nil object
EDIT2:
BTW, I missed this, and it may not make a difference, but the parser object has no property "delegate", you technically should be using the setter:
[parser setDelegate:self];
Also, you did implement the following, right?
parserDidStartDocument: // which I assume you never see, right
parser:validationErrorOccurred:
parser:parseErrorOccurred:
parserDidEndDocument: // you never see this either?
If parser is nil, dump the whole returned data as a UTF8 string (per the log code). Also, try looking for an error:
dispatch_async(dispatch_get_main_queue(), ^
{
NSLog(#"PARSE ERROR: %#", [parser parseError]);
} );

How to send multiple parameterts to PHP server in HTTP post

I'm sending base64 string to php server and its working well. Now I want to send another parameter as a string. Can anyone tell me what code need to add in below code.
Below code is working good for single parameter. How can we modify it for multiple parameters?
NSData *data = [UIImageJPEGRepresentation(imgeview.image,90) base64Encoding];
// Create your request string with parameter name as defined in PHP file
NSString *myRequestString = [NSString stringWithFormat:#"question_image=%#",data];
myRequestString = [myRequestString stringByReplacingOccurrencesOfString:
#"+" withString:#"%2B"];
// Create Data from request
NSData *myRequestData = [NSData dataWithBytes:[myRequestString UTF8String]
length:[myRequestString length]];
request = [[NSMutableURLRequest alloc] initWithURL:
[NSURL URLWithString:#"http://192.168.0.101/Mobile_tutor/webservice/question_details.php"]];
// set Request Type
[request setHTTPMethod:#"POST"];
// Set content-type
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
// Set Request Body
[request setHTTPBody:myRequestData];
// Now send a request and get Response
NSData *returnData = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error: nil];
// Log Response
NSString *response = [[NSString alloc] initWithBytes:[returnData bytes]
length:[returnData length]
encoding:NSUTF8StringEncoding];
NSLog(#"-------------%#",response); // here you get reasponse string
For the network operation these is better supporting API like AFNetworking available witch work async and way better to handle
Tutorials for AFNetworking
Get from here
NSArray *keys = #[#"UserID", ];
NSArray *objects = #[#(userId)];
NSDictionary *parameter = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:
[NSURL URLWithString:BaseURLString]];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
[httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"services/UserService.svc/GetUserInfo"
parameters:parameter];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSError* error = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if ([jsonObject isKindOfClass:[NSDictionary class]]) {
// do what ever
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
Given a NSDictionary "params" whose keys and values are strings and where every entry represents one parameter (name/value) you can define a helper category:
#interface NSDictionary (FormURLEncoded)
-(NSData*) dataFormURLEncoded;
#end
dataFormURLEncoded returns a properly encoded character sequence from the given parameters in the dictionary.
The encoding algorithm is specified by w3c: URL-encoded form data / The application/x-www-form-urlencoded encoding algorithm
It can be implemented as follows:
First, a helper function which encodes a parameter name, respectively a parameter value:
static NSString* x_www_form_urlencoded_HTML5(NSString* s)
{
// http://www.w3.org/html/wg/drafts/html/CR/forms.html#application/x-www-form-urlencoded-encoding-algorithm , Editor's Draft 24 October 2013
CFStringRef charactersToLeaveUnescaped = CFSTR(" ");
CFStringRef legalURLCharactersToBeEscaped = CFSTR("!$&'()+,/:;=?#~");
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)s,
charactersToLeaveUnescaped,
legalURLCharactersToBeEscaped,
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:#" " withString:#"+"];
}
Finally, dataFormURLEncoded composes the character sequence of the encoded parameters. A "parameter" will be composed by concatenating the encoded name, = and encoded value:
parameter := name "=" value
Then, the parameter list will be composed by concatenating the parameters by separating them by a "&":
parameters := parameter ["&" parameter]
It can be implemented as below:
#implementation NSDictionary (FormURLEncoded)
-(NSData*) dataFormURLEncoded {
NSMutableData* data = [[NSMutableData alloc] init];
BOOL first = YES;
for (NSString* name in self) {
#autoreleasepool {
if (!first) {
[data appendBytes:"&" length:1];
}
NSString* value = self[name];
NSData* encodedName = [x_www_form_urlencoded_HTML5(name) dataUsingEncoding:NSUTF8StringEncoding];
NSData* encodedValue = [x_www_form_urlencoded_HTML5(value) dataUsingEncoding:NSUTF8StringEncoding];
[data appendData:encodedName];
[data appendBytes:"=" length:1];
[data appendData:encodedValue];
first = NO;
}
}
return [data copy];
}
#end
Note: The character sequence encodes the strings using Unicode UTF-8.
Example:
Given your parameters:
NSDictionary* params = #{#"a": #"a a", #"b": #"b+b", #"c": #"ü ö"};
NSData* encodedParamData = [params dataFormURLEncoded];
Now, encodedParamData will be added to your body whose content type is application/x-www-form-urlencoded.
The encoded parameter string becomes:
a=a+a&b=b%2Bb&c=%C3%BC+%C3%B6

Different NSString results from URL download

I am parsing a string that I obtain from a website but get different results depending on how I download.
This way it works:
NSString *tagiString = #"http://tagesanzeiger.ch";
NSURL *tagiURL = [NSURL URLWithString:tagiString];
NSError *error;
NSString *text =[NSString stringWithContentsOfURL:tagiURL
encoding:NSASCIIStringEncoding
error:&error];
Te following way it does not work. I first download the data, feed it into the NSMutableData *articleData and then convert to a NSString with initWithData:encoding:
- (void)downloadWebsite
{
NSString *tagiString = #"http://tagesanzeiger.ch";
NSURL *websiteURL = [NSURL URLWithString:tagiString];
NSURLRequest *request = [NSURLRequest requestWithURL:websiteURL];
connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self
startImmediately:YES];
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[articleData appendData:data];
}
- (NSString *)data
{
NSString *text = [[NSString alloc] initWithData:articleData
encoding:NSSymbolStringEncoding];
return text;
}
Seems like the resulting NSString *text content is not the same for both versions? Do I need to use a different string encoding? I have tried many without success.
Implement the delegate method connectionDidFinishLoading to ensure the connection loading has finished where you can call your data method. Also try to use NSASCIIStringEncoding instead of
NSSymbolStringEncoding.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *text = [[NSString alloc] initWithData:self.articleData
encoding:NSASCIIStringEncoding];
//do whatever you need to do with the text
}
Yes, you need to use a different string encoding. You can try NSUTF8StringEncoding. Here it's working for me. And utf-8 is almost the most popular encoding way.

Web service method not hit when called via Objective C

My App_Code/IGetEmployees.vb file
<ServiceContract()> _
Public Interface IGetEmployees
<OperationContract()> _
<WebInvoke(Method:="POST", ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="json/contactoptions")> _
Function GetAllContactsMethod(strCustomerID As String) As List(Of NContactNames)
End Interface
My App_Code/GetEmployees.vb file
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Function GetAllContactsMethod(strCustomerID As String) As List(Of NContactNames) Implements IGetEmployees.GetAllContactsMethod
Utilities.log("Hit get all contacts at 56")
Dim intCustomerID As Integer = Convert.ToInt32(strCustomerID)
Dim lstContactNames As New List(Of NContactNames)
'I add some contacts to the list.
Utilities.log("returning the lst count of " & lstContactNames.Count)
Return lstContactNames
End Function
NContactNames is a class with 3 properties.
So i am using ASP.NET web services to retrieve information from SQL server and pass it to my iPad in JSON format. I have a problem with parameter passing. So like you see i have 2 files IGetEmployees.vb and GetEmployees.vb. I am implementing the method GetAllContactsMethod. What's happening is the two lines in GetEmployees.vb file (Utilities.log), they never get logged. The function is not getting called at all.
My objective c code to call this function
NSString *param = [NSString stringWithFormat:#"strCustomerID=%#",strCustomerID];
jUrlString = [NSString stringWithFormat:#"%#",#"http://xyz-dev.com/GetEmployees.svc/json/contactoptions"];
jurl = [NSURL URLWithString:jUrlString];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:jurl];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[param dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(#" request string is %#",[[request URL] absoluteString]);
NSLog(#"Done");
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if(theConnection)
{
jData = [NSMutableData data];
NSError *jError;
NSMutableDictionary *json =[NSJSONSerialization JSONObjectWithData:jData options:kNilOptions error:&jError];
NSLog(#"%#",json); //Gets Here and prints (null)
NSLog(#"Done"); //prints this as well.
}
else
{
NSLog(#"No");
}
At the time of posting this code the "if" statement is true and (null) is printed followed by "Done"
The output of my absolute request is:
request string is http://xyz-dev.com/GetEmployees.svc/json/contactoptions
This is the first time i am writing json to accept parameters. So i might be missing something.What is it?Why is the function not getting called at all on the Visual Studio side. If you need more info please ask.Thanks...
this is the moethod in Objetive-C, for that.
-(void) insertEmployeeMethod
{
if(firstname.text.length && lastname.text.length && salary.text.length)
{
NSString *str = [BaseWcfUrl stringByAppendingFormat:#"InsertEmployee/%#/%#/%#",firstname.text,lastname.text,salary.text];
NSURL *WcfSeviceURL = [NSURL URLWithString:str];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:WcfSeviceURL];
[request setHTTPMethod:#"POST"];
// connect to the web
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// NSString *respStr = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:respData
options:NSJSONReadingMutableContainers
error:&error];
NSNumber *isSuccessNumber = (NSNumber*)[json objectForKey:#"InsertEmployeeMethodResult"];
//create some label field to display status
status.text = (isSuccessNumber && [isSuccessNumber boolValue] == YES) ? [NSString stringWithFormat:#"Inserted %#, %#",firstname.text,lastname.text]:[NSString stringWithFormat:#"Failed to insert %#, %#",firstname.text,lastname.text];
}
}
Before to run the code, test your URL with POSTMAN, is an app from Google Chrome.
regards.

Resources