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.

Nactus
  • 702
  • 2
  • 13
  • 35
  • 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. – chancyWu Nov 19 '13 at 04:09
  • 1
    The [sample code](https://developer.apple.com/library/ios/samplecode/SeismicXML/Listings/SeismicXML_APLParseOperation_m.html#//apple_ref/doc/uid/DTS40007323-SeismicXML_APLParseOperation_m-DontLinkElementID_11) shows exactly how to do this. It's the second result in a google search. – user1118321 Nov 19 '13 at 04:17
  • up-voted for the link – Nactus Nov 19 '13 at 04:22
  • 1
    @Chancy, can I have an example please – Nactus Nov 19 '13 at 04:23
  • @Nactus you can try this http://stackoverflow.com/questions/4705588/nsxmlparser-example – chancyWu Nov 19 '13 at 04:27

4 Answers4

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;
    }
}
manujmv
  • 6,450
  • 1
  • 22
  • 35
  • @Nactus if you want any more help just ask – manujmv Nov 19 '13 at 04:30
  • 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 Nov 19 '13 at 08:42
  • @Nactus ok i found the problem. there was an item node inside congress_numbers. i changed my code. include the modified code – manujmv Nov 19 '13 at 09:07
  • 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. – Nactus Nov 19 '13 at 09:34
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.

chancyWu
  • 14,073
  • 11
  • 62
  • 81
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
    {

    }
User558
  • 1,165
  • 1
  • 13
  • 37
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);
       }];
iCoder
  • 1,298
  • 1
  • 9
  • 25