We recently ran into a huge roadblock. We had created an XMPP framework in Cocoa, and we were hoping it would easily port to the iPhone. Turns out we were wrong, because Apple decided to make the NSXML classes (NSXMLDocument, NSXMLElement, NSXMLNode, etc) private! They are supposedly in the private Office framework, however private frameworks can’t be used for any intensive purposes. So there we were, heavily invested in NSXML, and Apple pulls the floor out from under our feet. Some web searching quickly revealed that we weren’t the only ones in this particular situation. It would seem that Apple is more interested in supporting gaming these days…

So with the NSXML class cluster missing from the iPhone, what are our options?

– The NSXMLParser is available. This gives you a SAX parser, and would be helpful if we only needed to read XML. The problem was, we needed to generate a bunch of XML too, so this only gets us halfway there. Plus if we went this route, we’d have to rewrite all the existing code that already uses NSXMLDocument.

– libxml2 is available on the iPhone. This is a C library that’s been around for a long time, and it’s been available in OS X since like 10.3.9 (or maybe even earlier). This is certainly an option… but it’s in C! Surely somebody’s made an Objective-C wrapper for it right? Most people think NSXML is a wrapper around libxml. But even if that’s true it doesn’t help us.

– The Coconut Framework is an Objective-C wrapper around libxml. It’s distributed under GPL (but with the possibilty of LGPL or BSD if you talk to the author). It uses a different API than NSXML, likely because it’s been around for awhile and NSXML was only added in 10.4. Also, it seems you can only use it to read XML but not generate it.

– TouchXML is another Objective-C wrapper around libxml. It’s under a non-restrictive MIT license, and operates as an NSXML replacement. BUT – it gives you read-only support for XML.

– Google’s GDataXML classes were the closest I could get. Distributed under the Apache license, they offer an Objective-C wrapper around libxml, and they operate as an NSXML replacement. Plus they offer the ability to read XML, and generate XML with methods such as elementWithName:, addAttribute:, addChild:, etc.

– We present another solution below. Keep reading…

So as a framework developer, with other developers in mind, I had to decide what to do.

If I used Google’s GDataXML classes, then I could quickly patch the problem. (I’d only need to define the NSXML classes as GDataXML classes on the iPhone.) But it would offer only a small, small subset of what NSXML offers. Developers using the framework on the iPhone would have to realize this and compensate. Alternatively, I could switch all my code to use the GDataXML classes, but then developers on OS X would reasonably think I’m an idiot.

Also, as I was skimming the source code of all these frameworks I realized something – they are all rather primitive, and don’t always operate as NSXML does, and sometimes behave counter-intuitively in an Objective-C world. For example:

- (void)method1
    node1 = [[NSXMLElement elementWithName:@"node1"] retain];
    node2 = [[NSXMLElement elementWithName:@"node2"] retain];
    [node1 addChild:node2];
- (void)method2
    NSLog(@"node2: %@", [node2 name]);
    [node1 release];
    NSLog(@"node2: %@", [node2 name]);

Run this code, and you get the name of node2 printed twice. This makes sense from an Objective-C standpoint. (node2 was never released, why would it’s name disappear?) But what happens with other frameworks? Try something similar with TouchXML and it doesn’t work the same way. Why? Becuase freeing node1 calls xmlNodeFree, which in turn frees all its children including the xmlNodePtr that node2 was wrapping. It works fine with GDataXML – but only because they “cheat” and copy xmlNode subtrees in their addChild: method, which seems a little wasteful considering how most people would use the API. For example:

NSXMLElement *queryNode, *usernameNode, *digestNode, *resourceNode;

queryNode = [NSXMLElement elementWithName:@"query" URI:@"jabber:iq:auth"];
usernameNode = [NSXMLElement elementWithName:@"username" stringValue:username];
digestNode = [NSXMLElement elementWithName:@"digest" stringValue:digest];
resourceNode = [NSXMLElement elementWithName:@"resource" stringValue:resource];

[queryNode addChild:usernameNode];
[queryNode addChild:digestNode];
[queryNode addChild:resourceNode];

NSXMLElement *iqNode = [NSXMLElement elementWithName:@"iq"];
[iqNode addAttributeWithName:@"type" stringValue:@"set"];
[iqNode addChild:queryElement];

In the example above, the GDataXML classes would create the username node once, then copy it so it can be added. The same would happen to the digest and resource nodes. And then the whole queryNode would get copied as well when it’s added to the iqNode. Build up a big XML fragment like this, or build up many XML fragments, and there’s a lot of wasteful copying going on. And building XML fragments is what our XMPP framework is all about.

There is an inherent danger in using an XML API that acts differently than Apple’s. What happens if Apple makes it’s NSXML classes public in a future update? We’d probably want to switch the framework to use them – but what if iPhone developers using the framework had already adapted to the alternative XML library. If that library operates differently than NSXML, then the switch could break a lot of code. Plus there’s another problem: alot of iPhone developers are also Mac developers. And they would write a single library that would be used both on the desktop and on the phone. And in fact the XMPP framework itself fits into this category.

An optimal solution would be something like this:

– An Objective-C wrapper around libxml
– Ability to read XML
– Ability to generate XML
– Same API as NSXML
– Behaves the same as NSXML
– Behaves like a true Objective-C class

So I decided to write just this. I’m releasing the source code for iPhone developers everwhere in hopes that they never have to directly use libxml themselves, and so that if Apple ever does make their NSXML classes public, the transition can be seamless. I’m calling the framework KissXML, in honor of TouchXML which inspired me to write it. (Sorry Google, I didn’t find out about your code until I was already halfway done.)

KissXML Google Code Project Page