Tuesday, November 6, 2018

Parse XML file Objective C

In this post, I am going to explain how to parse an XML file for iOS 10.0 using Objective C. There are lots of XML parser available for iOS. Here I am using
NSXMLParser, which is a SAX (Simple API for XML) parser and comes by default with iPhone SDK. This parser is written in Objective C and very easy to use.

My XCode version is 8.3 (latest one so far). So if you are using the lower version of it the look can be different. But it will work fine.

Now it's time for the XML file. In this project, the XML file I am using looks like Image 1. The cars tag is holding four car tag in it. It will be easy to understand if we convert it in a tree view. Look at the Image 2. So, when we are going to parse this file we will get a nested array where carsArray will contain four carDictionary (Here you can use another Array but you have to remember the index number which is a complex thing). Each of this dictionary going to have five attributes (Type, Description, Popularity, Example and Image). Here I am using a local XML file. But the procedure is same for online XML.
Image 2: Tree view of the XML file


Image 1: The sample XML file














Open Xcode. From the Menu  select File -> New -> Project (Image 3). Then select "Single View Application" (Image 4). After that, you see a screen like Image 5. Provide Product Name, Organization Name and Organization identifier. You can use your organization name and XCode will automatically generate the organization identifier though you can change it later and for product name use the name you want to use for your app. I have named this product "XML_Parser".


Image 3: Creating New Project
Image 4: Selecting Single View Application












After this add the XML file in your project (Gif 1). If you are working with online XML this step is not for you. Open "ViewController.h" in your project. Then add NSXMLParser Delegate here. Your ViewController header file should look like Image 5. Now open the implementation file of ViewController. In viewDidLoad method add :

NSString *xmlPath = [[NSBundle mainBundle] pathForResource:@"Cars" 
ofType:@"xml"];
NSData *xmlData = [NSData dataWithContentsOfFile:xmlPath];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:xmlData];
[xmlParser setDelegate:self];
[xmlParser parse];

Gif 1: Adding XML file in project


If you are using online XML file then add
NSXMLParser *xmlparser = [[NSXMLParser alloc] init:
[NSURL URLWithString:@"urlWithXML"]];
[xmlParser setDelegate:self];
[xmlParser parse];

Image 5- Header file with NSXMLParser Delegate

You should be able to build your project successfully.

In the next step we are going to collect the data from XML file in a local data memory (eg. NSArray) so that we can use it easily later in the project.

With the above code snippet, we have just started the parsing procedure and set the NSXMLParser delegate. But we did not implement the delegate method yet. With implementing these delegate methods we can generate a local memory. Every XML file has basically three things.Together all of these three things is knows as XML element.

1. a start tag (eg. <cars> ,<car>,<type>)
2. a end tag (eg </cars> , </car>, </type>)
3. value between this start and end tag. It could be a text, it could be another start end tag or all them together. (eg. Hatchback, <car>....</car>,<type>.......</type>)

There are three main delegate methods of NSXMLParser to parse an XML element, with these methods we can easily construct an NSArray. (Image 6)

Image 6 - Delegate methods in the implementing file


- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
attributes:(NSDictionary *)attributeDict;{
}

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

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;{
}




Now the first delegate method says "didStartElement", It will look for the start tag, the second method ,"foundCharacters", will read the value and the last one, "didEndElement", will find the end tag. The parser parse the XML file line by line. In the Gif 2 I have tried to explain how this parser is parsing the XML file .

Gif 2: Gif 2 - Parsing Process by XML parser


Let's go back to the project. In "ViewController.h" add (Image 7)

Image 7 - Adding propertise in header file


@property (nonatomic,strong) NSMutableArray *carsArray;
@property (nonatomic,strong) NSMutableString *xmlValue;
@property (nonatomic,strong) NSMutableDictionary *carDictionary;

Then add  the delegate methods in the implementation file of "ViewController" (Image 6). Now we have to add necessary code in these methods. Let's start with "didStartElement" due to it is the first step of the parser. As mentioned before this method will find the start tag. If we look at the Image 1 (our XML file), the first start tag is <cars>. So when this method will find out element name “cars” then we are going to initialize our carsArrary. Same goes for <car> tag and carDictionary. So in this method add  (Image 8):

if ([elementName isEqualToString:@"cars"]) {
        _carsArray = [[NSMutableArray alloc] init];
    }
if ([elementName isEqualToString:@"car"]) {
        _carDictionary = [[NSMutableDictionary alloc] init];
    }


Image 8 - didStartElement method


The next step is "foundCharacters". In this method we will get the value between two tags. These two tags do not always mean a start tag and an end tag. They could be two start tags. The value between tags could be a text or collection of characters. To get the value between tags just add (Image 9):


if (!_xmlValue) {
        _xmlValue = [[NSMutableString alloc] initWithString:string];
    }
    else {
        [_xmlValue appendString:string];
    }


Image 9 - foundCharacters method


The final step is "didEndElement". This method search for the end tag of the XML element. If you are following this tutorial, we can see at this point we have the start tag ( ex. <cars>, <car>,<type>) and the value between these tags. Now with the last step, we will have full XML element. (ex. <type>Hatchback</type>). That means we could make the carDictionary with value and key and then we can insert this dictionary in the carsArray in this method. Making dictionary is done by adding :

if ([elementName isEqualToString:@"type"]
|| [elementName isEqualToString:@"description"]||
[elementName isEqualToString:@"popularity"]
|| [elementName isEqualToString:@"example"]
|| [elementName isEqualToString:@"image"]) {
 [_carDictionary setObject:_xmlValue forKey:elementName]; 
/// making the carDictionary with value and key..
 }

We will get the final carsArray by adding :
if ([elementName isEqualToString:@"car"]) {
        [_carsArray addObject:_carDictionary]; /// creating the carsArray.
    }

After adding all the codes in the "didEndElement" method it should look like Image 10.

Image 10 - didEndElement method


Doing all the steps successfully  if you load the carsArray in a UITableView then it will look like Image 11. Hopefully, this tutorial helped you to understand the parsing process of XML parser easily.

Image 11 - Final look after XML parsing




No comments:

Post a Comment