I've familiarized myself with the NSXMLParser from the iPhone SDK but I find the event-driven nature of it awkward for my purposes. I just want to extract some element values but this concept of having to handle the startElement, foundCharacters, and endElement seems like more work than it really should be. Am I just looking at this the wrong way or is there a simpler tree/DOM-based way of working with XML in the iPhone SDK?
If the advice is to just work with NSXMLParser, are there certain design patterns I can use to keep my code from having 5 levels of nested ifs in the startElement method?
If you're on the iPhone, using tree-based parsing can be a prohibitive memory hog. Trust me, I've been there, and I've tried many different approaches over the last five months of development of my main iPhone application. Tree-based parsing works fine until you download someone's comment stream containing 400 very long comments, clocking in at about 600KB of raw data. Quite aside from the size of the resultant XML tree, the memory allocated internally while creating that tree can be enormous.
I wound up creating a variant of NSXMLParser which pulls data in from a supplied NSInputStream rather than using a single chunk of data, and which passes only 1KB at a time into libxml for handling (NSXMLParser uses libxml too, but passes 100% of the data in one go).
The source code is available on github (look in the StreamingXMLParser folder). You'll also find a delegate superclass in there; for most parsing needs you can subclass AQXMLParserDelegate and implement -start[Element]WithAttributes: (NSDictionary *) attrs
and -end[Element]
in your subclass. These methods will be called for you as start & end tags are discovered, and inside the end tag you can use self.characters
to access the content characters or CDATA of the element.
For more on the relative memory footprints of the different parsers (albeit on the Mac, not the iPhone) see my original blog post here and the followup on NSXMLDocument here.
Consider the following code snippet, that uses libxml2, Matt Gallagher's libxml2 wrappers and Ben Copsey's ASIHTTPRequest to parse an XML document.
The nodes
instance of type NSArray*
will contain NSDictionary*
objects that you can parse recursively to get the data you want.
Or, if you know the scheme of your XML document, you can write an XPath query to get you to a nodeContent
or nodeAttribute
value directly.
ASIHTTPRequest *request = [ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://stackoverflow.com/"];
[request start];
NSError *error = [request error];
if (!error) {
NSData *response = [request responseData];
NSLog(@"Root node: %@", [[self query:@"//" withResponse:response] description]);
}
else
@throw [NSException exceptionWithName:@"kHTTPRequestFailed" reason:@"Request failed!" userInfo:nil];
[request release];
...
- (id) query:(NSString *)xpathQuery withResponse:(NSData *)respData {
NSArray *nodes = PerformXMLXPathQuery(respData, xpathQuery);
if (nodes != nil)
return nodes;
return nil;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With