Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Objective-C

Objective-C Fundamentals - NSXMLParser

4.00/5 (1 vote)
2 Sep 2011CPOL7 min read 53.6K  
A Chapter excerpt from Objective-C Fundamentals
image002.jpgObjective-C Fundamentals
Developing iPhone & iPad Apps

By Christopher K. Fairbairn, Johannes Fahrenkrug, and Collin Ruffenach

Apple provides a class called NSXMLParser to iPhone developers. Developers use this class when parsing XML. This article from Objective-C Fundamentals shows that NSXMLParser provides delegate methods that handle every point of parsing for both XML- and DTD-based documents.

To save 40% on your next purchase use Promotional Code code40project when you check out at www.manning.com.

You may also be interested in…

Apple provides a class called NSXMLParser to iPhone developers. Developers use this class when parsing XML. Several open source alternatives to NSXMLParser are available and used by many developers, but we are going to look at the delegate methods of the standard Cocoa XML Parser.

There is no <NSXMLParser> protocol; you will receive no warning if you do not declare this in the header of the application you are creating. NSXMLParser is a fringe design class that follows the principles of protocol design but doesn’t explicitly define a protocol. An NSXMLParser object has a parameter called delegate, which needs to be defined. Whatever object is defined as the delegate has the option of implementing a collection of 20 different delegate methods. NSXMLParser provides delegate methods that handle every point of parsing for both XML- and DTD-based documents.

XML is a type of file that can hold data in a very structured manner. As a quick introduction, XML uses the syntax of HTML to create unique data structures. An example of an XML element that describes a person is shown in listing 1.

Listing 1 An Author in XML

<Author>
    <name>Collin Ruffenach</name>
    <age>23</age>
    <gender>male</gender>
    <Books>
           <Book>
                  <title>Objective C for the iPhone</title>
                  <year>2010</year>
                  <level>intermediate</level>
              </Book>
    </Books>
</Author>

XML is a very common means of getting data from online sources such as Twitter. XML is also used to facilitate the data required to run your specific iPhone project. iPhone development relies heavily on PLISTS. These files are really just XML.

DTD stands for Document Type Definition. This is a document that would describe the structure of the XML that you are going to work with. The document type definition for the XML in version 7.4.3.1 would be:

<!ELEMENT Author (name, age, gender, books_list(book*))>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT gender (#PCDATA)>
<!ELEMENT Book (title, year, level)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT level (#PCDATA)>

For some applications, examining the structure of the XML they are receiving will change the manner in which the application parses. In this case, we say that the XML will contain an element called Author. An Author will be defined by a name, age, and gender, which will be simple strings. An author will also have a list of Book elements. A Book is defined by a title year and level that are all simple strings. This ensures that the NSXMLParser knows what to do.

The majority of the time when you parse XML, you will be aware of its structure when writing your parser class. For these instances, you will not need to investigate the XML feeds DTD. An example of this would be the Twitter XML feed for a timeline. We will assume we know the XML structure for our XML and only implement the parsing functions of the NSXMLParser delegate to parse the Author XML we have already looked at.

Parsing an author with NSXMLParser delegate

The first step when implementing NSXMLParser is to create a class that will contain the parser object and implement its delegate methods. Let’s create a new view-based project called Parser_Project and create a new NSObject subclass called Parser. The only instance variables we are going to declare for the Parser class is an NSXMLParser and an NSMutableString to help. Make Parser.h look like the following.

#import <Foundation/
Foundation.h>
 
@interface Parser : NSObject <NSXMLParserDelegate>
{
    NSXMLParser *parser;
    NSMutableString *element;
}
 
@end

We are going to need to have an XML file to parse. You can take the XML in listing 2 and place it in a regular text file. Save the file as Sample.xml and add it into the project. This will give us a local XML file that we can reference to parse.

Now we need to fill in Parser.m. Parser.m will contain an initialize and the implementation of the three most common NSXMLParser Delegate methods. Let’s start with the initializer method and add the code shown in listing 2 into XMLParser.m.

Listing 2 Parser.m Initializer

-init {
   if(self == [super init]) {
          parser = [[NSXMLParser alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:@"Sample" ofType: @"xml"]]];
          [parser setDelegate:self];
          [parser parse];
   }      
   return self;
}

Here we are going to initialize our NSXMLParser parser using a file URL pointing to our Sample.xml file that we imported into our project earlier. NSURL is a large class with all sorts of initializers. In this case, we are telling it that we will be providing a path to a file URL, or a local resource. With that done, we tell the NSXMLParser that this class will be the delegate of the parser and, finally, we tell the NSXMLParser we are ready to parse by sending the parse exam.

Once the parse method is called on the NSXMLParser, the parser will begin to call its delegate methods. The parser reads down an XML file much like Latin/English characters are read: left to right, top to bottom. While there are many delegate methods, we will be focusing on three of them.

§  - (void)parser:(NSXMLParser
*)parser didStartElement:(NSString *)elementName namespaceURI:(NSString
*)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary
*)attributeDict

While this method has a lot of parameters passed into it, it is actually quite simple for our purposes. This method is called when an element is seen starting. This means that any element (between <>) that does not have a /. In this method we will first print the element we see starting and we will clear our NSMutableString element. You will see upon implementing the new methods that we use the element variable as a string that we add to as delegate methods are called. The element variable is meant to hold the value of only one XML element. So, when a new element is started, we make sure to clear it out. Fill out the following, shown in listing 3, for this delegate method.

Listing 3 NSXMLParser Methods

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

NSLog(@"Started
Element %@", elementName);
      element = [NSMutableString
string];

}

§  - (void)parser:(NSXMLParser
*)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName

This method is called when an element is seen ending. This means when an element has a / this method will be called. When this method is called out NSMutableString element variable will be complete. We will simply print out the value we have seen (see listing 4).

Listing 4 NSXMLParser Methods

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

      NSLog(@"Found an element named: %@ with a
value of: %@", elementName, element);

}

§  - (void)parser:(NSXMLParser
*)parser foundCharacters:(NSString *)string

This method is called when the parser sees anything between an element’s beginning and ending. We will use this entry point as a way to collect all the characters that are between an element; this is done by calling the appendString method on our NSMutableString. By doing this every time, this method is called; by the time the didEndElement method is called, the NSMutablrString will be complete. In this method, we first make sure that we have initialized our NSMutableString element and then we append the string we are provided, shown in listing 5.

Listing 5 NSXMLParser Methods

- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string 

 if(element == nil)

        element = [[NSMutableString
alloc] init];

 [element appendString:string];

}

Now all that is left to do is create an instance of our Parser and see it go. Go to Parser_ProjectAppDelegate.m and add the code shown in listing 6 into the already existing method.

Listing 6 Initializing the Parser

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWith Options:(NSDictionary *)launchOptions {    

    // Override point for customization after app launch    
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];

   Parser *parser = [[Parser alloc] init];

   return YES;
}

If you run the application and bring up the terminal window (shift + apple + r), the output shown in listing 7 should be generated.

Listing 7 Parser Output

Parser_Project[57815:207] Started Element Author
Parser_Project[57815:207] Started Element name
Parser_Project[57815:207] Found an element named: name with a
value of: Collin Ruffenach
Parser_Project[57815:207] Started Element age
Parser_Project[57815:207] Found an element named: age with a
value of: 23
Parser_Project[57815:207] Started Element gender
Parser_Project[57815:207] Found an element named: gender with a
value of: male
Parser_Project[57815:207] Started Element Books
Parser_Project[57815:207] Started Element Book
Parser_Project[57815:207] Started Element title
Parser_Project[57815:207] Found an element named: title with a
value of: Objective C for the iPhone
Parser_Project[57815:207] Started Element year
Parser_Project[57815:207] Found an element named: year with a
value of: 2010
Parser_Project[57815:207] Started Element level
Parser_Project[57815:207] Found an element named: level with a
value of: intermediate
Parser_Project[57815:207] Found an element named: Book with a
value of: intermediate
Parser_Project[57815:207] Found an element named: Books with a
value of: intermediate
Parser_Project[57815:207] Found an element named: Author with a
value of: intermediate

You can see that using the NSXMLParser delegate methods we successfully parsed all of the information in our XML file. From here, we could create Objective-C objects to represent the XML and use it throughout our application. XML processing is a vital part of most applications that get their content from some kind of web source; Twitter Clients, News Clients, or YouTube.

Summary

Protocols are all over the place when developing for the iPhone. They are one of the foundation design decisions for the majority of the classes the Apple provides. With attentive coding, the usage of these protocols can make your application efficient and error proof. Through a proper understanding and implementation of the protocol design method, you can ensure a well-designed application.

NSXMLParser is a fringe design class that follows the principles of protocol design but doesn’t explicitly define a protocol. An NSXMLParser object has a parameter called delegate, which needs to be defined. Whatever object is defined as the delegate has the option of implementing a collection of 20 different delegate methods. NSXMLParser provides delegate methods that handle every point of parsing for both XML- and DTD-based documents.

Here are some other Manning titles you might be interested in:

image003.jpg

iPhone and iPad in Action
Brandon Trebitowski, Christopher Allen, and Shannon Appelcline

image004.jpg

iPhone in Practice
Bear P. Cahill

image005.jpg

iPad in Practice
Paul Crawford

Last updated: August 27, 2011

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)