2

I'm trying to parse this xml file. The problem I'm having is that I'd like to use the -(void)parser:(NSXMLParser*)parser didStartElement ... to drill down into several levels of this xml file.

This is what I have so far:

#pragma didStartElement (from the parser protocol)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    // Choose the tag
    if ([elementName isEqualToString:@"item"]) {

        NSString *firstName = [attributeDict valueForKey:@"firstname"];
        NSString *lastName = [attributeDict valueForKey:@"lastname"];
        NSString *birthDay = [attributeDict valueForKey:@"birthday"];

        Politician *politician = [[Politician alloc] initWithName:firstName lName:lastName bDay:birthDay];

        if (politician != nil) {

            [people addObject:politician];
        }
    }

}

The problem is that this code does not drill down. Is there a way to selectively start the parsing from a specific tag (say: person) and check for the keys of that tag or to rewrite the "elementName's" value so I can use multipe if statements? What's the right way of doing this? Thanks much.

5
  • 1
    you can new a Politician in the didStartElement,and assign the property in the foundCharacters. add the Politician to the people in the didEndElement. Commented Nov 19, 2013 at 4:09
  • 1
    The sample code shows exactly how to do this. It's the second result in a google search. Commented Nov 19, 2013 at 4:17
  • up-voted for the link Commented Nov 19, 2013 at 4:22
  • 1
    @Chancy, can I have an example please Commented Nov 19, 2013 at 4:23
  • @Nactus you can try this stackoverflow.com/questions/4705588/nsxmlparser-example Commented Nov 19, 2013 at 4:27

4 Answers 4

5

You couldnt get the firstname,lastname,etc in your attributeDict. Attribute dictionary holds values like in the below format

<count n="1">

In the above example attributeDict holds the value for n

In order to parse the given xml, you can use the below code.

Declare the objects

Politician *politician;
NSString *curElement;
NSMutableArray *politicians;
BOOL isCongressNumbers;

Initialize the politicians in viewDidLoad

politicians = [[NSMutableArray alloc]init];

Add the delegate methods

#pragma mark - NSXMLParser Delegate

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"item"]) {
        politician = [[Politician alloc]init];

    } else if ([elementName isEqualToString:@"congress_numbers"])  {
        isCongressNumbers = YES;
    }

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    curElement = string;


}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"item"]  && !isCongressNumbers) {
        [politicians addObject:politician];
    } else if ([elementName isEqualToString:@"firstname"])  {
        politician.name = curElement;
    } else if ([elementName isEqualToString:@"lastname"])  {
        politician.lName = curElement;
    } else if ([elementName isEqualToString:@"birthday"])  {
        politician.bDay = curElement;
    } else if ([elementName isEqualToString:@"congress_numbers"])  {
        isCongressNumbers = NO;
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

@Nactus if you want any more help just ask
some help would be great, actually. I tried your example and the objects that are added unto "politicians" are all empty (0x00000). What would be the best way to chat about this? I suppose it would take more than a few comments to understand what's going on.
@Nactus ok i found the problem. there was an item node inside congress_numbers. i changed my code. include the modified code
I will accept your answer for being the most explicit. Thanks for your help. I had to adjust it a bit to fit my own code, but it works.
4

You can
1) new a Politician in the didStartElement method and assign the element name in one instance variable.

2) assign the properties of Politician in the foundCharacters according to the instance variable you assigned in 1).

3) add the Politician to the people in the didEndElement.

Hope this is helpful.

The sample code is as follows:

declare some instance variables:

Politican *politican;
NSString *currentElement;
NSMutableArray *politicians;

init the arrays:

politicians = [[NSMutableArray alloc] init];

implement the delegate methods.

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    currentElement = elementName;
    if ([elementName isEqualToString:@"item"]) {
        politician = [[Politician alloc] init];
    }

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    if([string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length<1)
        return;  // avoid some white space

    if ([currentElement isEqualToString:@"firstname"])  {
        politician.firstname = string;
    } else if ([currentElement isEqualToString:@"lastname"])  {
        politician.lastname = string;
    } else if ([currentElement isEqualToString:@"birthday"])  {
        politician.birthday = string;
    }

}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"item"]) {
        [politicians addObject:politician];
    } 
}

Anyway this is just a sample, you'd better write all the if else statements according to your xml.

In your xml file, there are several tags named the same item. you can try to make one more instance variable to store the previous tag to make the difference and do the assignments.

2 Comments

can I have an example, please ?
in your example the xml file has only one level of nesting. in my file there are three or more levels of nesting. (example: <item><person><firstname>).
2
    In.h file
    @property (strong, nonatomic) NSXMLParser *xmlParser;
    @property (nonatomic, retain) NSMutableDictionary *lResponseDict;
    @property (nonatomic, weak) NSString *currentElement;

    NSString* UDID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    NSLog(@"UDID:: %@", UDID);
    NSString *urlString = [NSString stringWithFormat:@"urlHere"];
    NSString *jsonString = [NSString stringWithFormat:LOGIN,self.cUsernameTxtFld.text,self.cPasswordTxtFld.text,UDID];
    NSData *myJSONData =[jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"text/html" forHTTPHeaderField:@"Accept"];
    NSMutableData *body = [NSMutableData data];
    [body appendData:[NSData dataWithData:myJSONData]];
    [request setHTTPBody:body];
    NSError *error;
    NSURLResponse *response;
    NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    NSString *str = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
    if(str.length > 0)
    {
        self.xmlParser = [[NSXMLParser alloc] initWithData:urlData];
        self.xmlParser.delegate = self;
        // Start parsing.
        [self.xmlParser parse];
    }

   #pragma mark - NSXML Parsar Delegate Methods.
   - (void)parserDidStartDocument:(NSXMLParser *)parser
   {
     //    NSLog(@"Parsing Initiated.");
   }
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
   {
      self.currentElement = elementName;
      if([elementName isEqualToString:@"data"])
       {
         // NSLog(@"%@",elementName);
         self.lResponseDict = [[NSMutableDictionary alloc]init];
       }
   }
   - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
      {
        if([elementName isEqualToString:@"data"])
        {
            // NSLog(@"%@",elementName);
            NSLog(@"Final Dict: %@", _lResponseDict);
        }
      }
   - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
      //NSLog(@"%@", string);
      [_lResponseDict setObject:string forKey:_currentElement];
    }

   -(void)parserDidEndDocument:(NSXMLParser *)parser
    {

    }

Comments

1

Hope you are getting the URL data ... so with SMXMLParser, it is easier to parse using one by one node ...

In the below mentioned example, I am using AFNetworking with SMXMLParser . Hope you get the idea ....

    NSString *soapRequest=[NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
                               "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
                               "<soap:Body>\n"
                    // Your parameters here …. //
                               "</soap:Body>\n"
                               "</soap:Envelope>\n"];

        NSString *urlStr = @"Your URL";

        NSURL *urlNew = [NSURL URLWithString:urlStr];

        NSMutableURLRequest *request=[appDel generateRequestWithUrl:urlNew request:soapRequest];

        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

 NSError *error=nil;
            dictCarList = [[NSMutableDictionary alloc]init];
            SMXMLDocument *document=[[SMXMLDocument alloc]initWithData:operation.responseData error:&error];

            if (error) {
                NSLog(@"Error while parsing the document: %@", error);
                [indicatorView removeFromSuperview];
                return;
            }
            count++;

            SMXMLElement *element1 = [document.root childNamed:@"objects"];
            SMXMLElement *element2 = [element1 childNamed:@"The Tag you want to get"];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"Error:%@",error);
       }];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.