Skip to content

Instantly share code, notes, and snippets.

@takuma104
Created February 23, 2010 14:10
Show Gist options
  • Save takuma104/312186 to your computer and use it in GitHub Desktop.
Save takuma104/312186 to your computer and use it in GitHub Desktop.
/*
NSData+XMLParser
Simple XML Parser for iPhone
Usage:
* -I /usr/include/libxml2
* -L libxml2
Example:
NSData *xmlData = [NSData dataWithContentsOfFile:
[[NSBundle mainBundle] pathForResource:@"hoge" ofType:@"xml"]];
NSDictonary *root = [xmlData parseAsXML];
NSLog(@"dump: %@", root);
NSLog(@"Root node name: %@", [root nodeName]);
NSArray *children = [root childArray];
for (NSDictonary *n in children) {
NSLog(@"node name:%@ content:%@", [n nodeName], [n nodeContent]);
}
*/
///////////////////////////////////////////////////////////////////////////////
#import <libxml/tree.h>
#import <libxml/parser.h>
#import <libxml/HTMLparser.h>
#import <libxml/xpath.h>
#import <libxml/xpathInternals.h>
@interface NSData(XMLParser)
- (NSDictionary*)parseAsXML;
@end
@interface NSDictionary(XMLParser)
- (NSString*)nodeName;
- (NSString*)nodeContent;
- (NSArray*)attributeArray;
- (NSArray*)childArray;
- (NSString*)attributeContentByName:(NSString*)attributeName;
- (NSDictionary*)childNodeByNodeName:(NSString*)nodeName;
@end
@interface NSArray(XMLParser)
- (NSString*)attributeContentByName:(NSString*)attributeName;
- (NSDictionary*)childNodeByNodeName:(NSString*)nodeName;
@end
///////////////////////////////////////////////////////////////////////////////
@implementation NSDictionary(XMLParser)
- (NSString*)nodeName {
return [self valueForKey:@"nodeName"];
}
- (NSString*)nodeContent {
return [self valueForKey:@"nodeContent"];
}
- (NSArray*)attributeArray {
return [self valueForKey:@"nodeAttributeArray"];
}
- (NSArray*)childArray {
return [self valueForKey:@"nodeChildArray"];
}
- (NSString*)attributeContentByName:(NSString*)attributeName {
return [[self attributeArray] attributeContentByName:attributeName];
}
- (NSDictionary*)childNodeByNodeName:(NSString*)nodeName {
return [[self childArray] childNodeByNodeName:nodeName];
}
@end
@implementation NSArray(XMLParser)
- (NSString*)attributeContentByName:(NSString*)attributeName {
for (NSDictionary *d in self) {
if ([[d valueForKey:@"attributeName"] isEqualToString:attributeName]) {
return [d valueForKey:@"nodeContent"];
}
}
return nil;
}
- (NSDictionary*)childNodeByNodeName:(NSString*)nodeName {
for (NSDictionary *d in self) {
if ([[d nodeName] isEqualToString:nodeName]) {
return d;
}
}
return nil;
}
@end
@implementation NSData(XMLParser)
// original code by Matt Gallagher
// http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html
static NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult)
{
NSMutableDictionary *resultForNode = [NSMutableDictionary dictionary];
if (currentNode->name)
{
NSString *currentNodeContent =
[NSString stringWithCString:(const char *)currentNode->name encoding:NSUTF8StringEncoding];
[resultForNode setObject:currentNodeContent forKey:@"nodeName"];
}
if (currentNode->content && currentNode->type != XML_DOCUMENT_TYPE_NODE)
{
NSString *currentNodeContent =
[NSString stringWithCString:(const char *)currentNode->content encoding:NSUTF8StringEncoding];
if ([[resultForNode objectForKey:@"nodeName"] isEqual:@"text"] && parentResult)
{
currentNodeContent = [currentNodeContent
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *existingContent = [parentResult objectForKey:@"nodeContent"];
NSString *newContent;
if (existingContent)
{
newContent = [existingContent stringByAppendingString:currentNodeContent];
}
else
{
newContent = currentNodeContent;
}
[parentResult setObject:newContent forKey:@"nodeContent"];
return nil;
}
[resultForNode setObject:currentNodeContent forKey:@"nodeContent"];
}
xmlAttr *attribute = currentNode->properties;
if (attribute)
{
NSMutableArray *attributeArray = [NSMutableArray array];
while (attribute)
{
NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
NSString *attributeName =
[NSString stringWithCString:(const char *)attribute->name encoding:NSUTF8StringEncoding];
if (attributeName)
{
[attributeDictionary setObject:attributeName forKey:@"attributeName"];
}
if (attribute->children)
{
NSDictionary *childDictionary = DictionaryForNode(attribute->children, attributeDictionary);
if (childDictionary)
{
[attributeDictionary setObject:childDictionary forKey:@"attributeContent"];
}
}
if ([attributeDictionary count] > 0)
{
[attributeArray addObject:attributeDictionary];
}
attribute = attribute->next;
}
if ([attributeArray count] > 0)
{
[resultForNode setObject:attributeArray forKey:@"nodeAttributeArray"];
}
}
xmlNodePtr childNode = currentNode->children;
if (childNode)
{
NSMutableArray *childContentArray = [NSMutableArray array];
while (childNode)
{
NSDictionary *childDictionary = DictionaryForNode(childNode, resultForNode);
if (childDictionary)
{
[childContentArray addObject:childDictionary];
}
childNode = childNode->next;
}
if ([childContentArray count] > 0)
{
[resultForNode setObject:childContentArray forKey:@"nodeChildArray"];
}
}
return resultForNode;
}
- (NSDictionary*)parseAsXML {
xmlDocPtr doc = xmlReadMemory([self bytes],
[self length],
"",
NULL,
XML_PARSE_RECOVER);
if (doc == NULL) {
NSLog(@"Unable to parse.");
return nil;
}
NSDictionary *res = DictionaryForNode(xmlDocGetRootElement(doc), nil);
xmlFreeDoc(doc);
return res;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment