1
votes

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.)
3

3 Answers

1
votes

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];
0
votes

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];
0
votes

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]);
    } );