APXML: NSXMLDocument ’substitute’ for iPhone/iPod Touch
After spending some time working on Jabeh, my latest creation for iPhone/iPod Touch, I’m taking some time to dump a little learned knowledge into my blog.
In my first app, my XML needs weren’t that great, so putting up with the lack of NSXMLDocument in the iPhone SDK was not a big deal. However, in Jabeh I was changing the XML format so often and using so much of it for my network communication creating delegates for NSXMLParser quickly became a huge time sink. After a little hacking, I came up with APXML to solve my DOM problem. It’s not a perfect implementation of the W3C XML 1.0 standard, but it’s close enough for a lot of usage. One particular shortcoming is its lack of support for namespaces but maybe somebody else can add that support. If you just want to jump in and start using it (LGPL license), you can get the code from github:
http://github.com/arashpayan/apxml/
Most of my XML manipulation experience has been with various Java libraries (org.w3c.dom interface, JDOM and XOM), and the only one that I enjoyed using was XOM, because of its simplicity and licensing. Almost all of my design decisions were based on how XOM does things.
Let’s say we want to represent the following XML document in memory using APXML:
<book id="1" author="Michael Pollan">The Omnivore’s Dilemma</book>
<book id="2" author="Foley, van Dam, Feiner, Hughes">Computer Graphics: Principles and Practices</book>
</books>
In code, we do the following:
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// create the document with it’s root element
APDocument *doc = [[APDocument alloc] initWithRootElement:[APElement elementWithName:@"books"]];
APElement *rootElement = [doc rootElement]; // retrieves same element we created the line above
// create the first book entry (The Omnivore’s Dilemma)
APElement *book1 = [APElement elementWithName:@"book"];
[book1 addAttributeNamed:@"id" withValue:@"1"];
[book1 addAttributeNamed:@"author" withValue:@"Michael Pollan"];
[book1 appendValue:@"The Omnivore's Dilemma"];
[rootElement addChild:book1];
// create the second book entry (Computer Graphics)
APElement *book2 = [APElement elementWithName:@"book"];
[book2 addAttributeNamed:@"id" withValue:@"2"];
[book2 addAttributeNamed:@"author" withValue:@"Foley, van Dam, Feiner, Hughes"];
[rootElement addChild:book2];
}
@end
And if we want to convert the document to an NSString*, we use one of the two methods in APDocument:
NSString *xml = [doc xml];
or
NSString *prettyXML = [doc prettyXML];
Often times when I’m working with XML, I like to see what the current element contains, so for added convenience, you can obtain an XML string containing the element you’re working with, its attributes and all its children directly from the APElement by calling one of two methods:
- (NSString*)xml;
Now for the best part of the library, which is the ability to read in XML and represent it in APXML. All you have to execute is one simple line:
Hopefully this will be helpful to other developers out there. I may post another article soon if anybody has some questions.
UPDATE Sep 5, 2009: Here’s an example that demonstrates traversing the XML document.
NSLog(@"Root Element Name: %@", rootElement.name);
// get all the child elements (each book)
NSArray *childElements = [rootElement childElements];
for (APElement *child in childElements)
{
// returns the tag name
NSLog(@"Child Name: %@", child.name);
// reads the attribute named ‘author’
NSLog(@"Author: %@", [child valueForAttributeNamed:@"author"]);
// returns the text content of the element
NSLog(@"Title: %@", [child value]);
}
In the console you’ll see (I’ve removed the NSLog markup):
Root Element Name: books Child Name: book Author: Michael Pollan Title: The Omnivore’s Dilemma Child Name: book Author: Foley, van Dam, Feiner, Hughes Title: Computer Graphics: Principles and Practices
Comments
Can you post an example on how to use this library with loading XML from a URL? Thx.
@Danny
NSStringhas a class method that will let you synchronously get the data from a URL:+ (id)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)errorHi Arash, Thanks for the library. good work! I am trying to create an iphone app and need to read and process from xml file but i am very new to iphone dev and objective c. Can u tell me how to use APDocument to get data from a file. sorry if the question is very basic. (would really appreciate if you can email me some good examples to traverse xml from file and URL.) hope u have time! Thx -suha