Skip to content

Instantly share code, notes, and snippets.

@jeffkreeftmeijer
Created March 15, 2012 11:24
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jeffkreeftmeijer/2043748 to your computer and use it in GitHub Desktop.
Save jeffkreeftmeijer/2043748 to your computer and use it in GitHub Desktop.
Objective-C XML parser
#import <Foundation/Foundation.h>
@interface XmlParser : NSObject <NSXMLParserDelegate>
@property (strong, nonatomic) NSData *xmlData;
@property (strong, nonatomic) NSMutableDictionary *dictionary;
@property (strong, nonatomic) NSMutableDictionary *currentNode;
@property (strong, nonatomic) NSMutableDictionary *currentParentNode;
- (id)initWithXMLData:(NSData *)xmlData;
- (NSMutableDictionary *)dictionary;
@end
#import "XmlParser.h"
@implementation XmlParser
@synthesize xmlData = _xmlData, dictionary = _dictionary, currentNode = _currentNode, currentParentNode = _currentParentNode;
- (id)initWithXMLData:(NSData *)xmlData
{
if(self = [super init]){
_xmlData = xmlData;
}
return self;
}
- (NSMutableDictionary *)dictionary
{
if(!_dictionary){
_dictionary = [[NSMutableDictionary alloc] init];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:self.xmlData];
parser.delegate = self;
[parser parse];
}
return _dictionary;
}
- (NSMutableDictionary *)currentNode
{
if(!_currentNode){
_currentNode = _dictionary;
}
return _currentNode;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSMutableDictionary *node = [[NSMutableDictionary alloc] init];
[self.currentNode setObject:node forKey:elementName];
self.currentParentNode = self.currentNode;
self.currentNode = node;
if([attributeDict count] != 0)
{
[self.currentNode setObject:attributeDict forKey:@"attributes"];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
self.currentNode = self.currentParentNode;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSString *trimmedString = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if([trimmedString length] != 0){
[self.currentNode setObject:trimmedString forKey:@"value"];
}
}
@end
@ant512
Copy link

ant512 commented Jun 14, 2013

There are a number of problems with this code. The most significant is the use of the "currentNode" and "currentParentNode" method of keeping track of the XML tree. Two nodes means you can only have an XML document with a single level of node nesting before you lose track of where you are and both nodes point to each other.

To fix it, replace the "currentParentNode" with a stack.

@ant512
Copy link

ant512 commented Jun 19, 2013

...and then there's the problem with this fragment:

<parent><child>A</child><child>B</child></parent>

Subnodes with the same name collide in the dictionary, and the last subnode is the only one represented in the final structure. This is what we get for the above fragment:

parent {
    child {
        value {
            B
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment