📜 ⬆️ ⬇️

Parsing XML in NSDictionary using libxml

In the project for the iPhone, I was faced with the need to parse a large number of xml responses from the server. I would like to share my solution to parsing XML in NSDictionary.

XML of the form (some root element must be present, in the result example):
<result success="true">
<item>Value</item>
<item attr="val" />
<item code="item">value</item>
</result>

will be converted to:
 NSDictionary { "name" => "result", "attr" => NSDictionary { "success" => "true" }, "child" => NSArray { 0 => NSDictionary { "name" => "item", "value" => "value" }, 1 => NSDictionary { "name" => "item", "attr" => NSDictionary { "code" => "item" } }, 2 => NSDictionary { "name" => "item", "attr" => NSDictionary { "attr" => "val" }, "value" => "value" } } 
NSDictionary { "name" => "result", "attr" => NSDictionary { "success" => "true" }, "child" => NSArray { 0 => NSDictionary { "name" => "item", "value" => "value" }, 1 => NSDictionary { "name" => "item", "attr" => NSDictionary { "code" => "item" } }, 2 => NSDictionary { "name" => "item", "attr" => NSDictionary { "attr" => "val" }, "value" => "value" } }

Actually the methods themselves:
 /*  xml   */ - (NSDictionary *)xmlToDict { NSDictionary *resultDict = [NSDictionary dictionary]; if (self.content != nil) { xmlDocPtr doc = xmlParseMemory([self.content bytes], [self.content length]); if (!doc) { //    NSLog(@"error"); } else { xmlNode *root = NULL; root = xmlDocGetRootElement(doc); resultDict = [NSDictionary dictionaryWithDictionary:[self getNodeInfo:root]]; xmlFree(root); } } return resultDict; } /*   xml ,  */ -(NSDictionary *)getNodeInfo:(xmlNode *)node { NSMutableDictionary *itemDict = [[[NSMutableDictionary alloc] initWithCapacity:1] autorelease]; xmlChar *value = NULL; xmlAttr *attribute = NULL; if (node && node->name && ![[NSString stringWithCString:(char *)node->name encoding:NSUTF8StringEncoding] isEqualToString:@"text"]) { /*   */ value = (xmlChar*)node->name; [itemDict setObject:[NSString stringWithCString:(char *)value encoding:NSUTF8StringEncoding] forKey:@"name"]; xmlFree(value); /*   */ attribute = node->properties; NSMutableDictionary *attrDict = [[NSMutableDictionary alloc] initWithCapacity:1]; while(attribute && attribute->name && attribute->children) { value = xmlNodeListGetString(node->doc, attribute->children, 1); [attrDict setObject:[NSString stringWithCString:(char *)value encoding:NSUTF8StringEncoding] forKey:[NSString stringWithCString:(char *)attribute->name encoding:NSUTF8StringEncoding]]; xmlFree(value); attribute = attribute->next; } [itemDict setObject:attrDict forKey:@"attr"]; [attrDict release]; /*   */ value = xmlNodeGetContent(node); [itemDict setObject:[NSString stringWithCString:(char*)value encoding:NSUTF8StringEncoding] forKey:@"value"]; xmlFree(value); /*   */ NSMutableArray *childArray = [[NSMutableArray alloc] initWithCapacity:1]; xmlNode *child = NULL; for (child = node->children; child != NULL; child = child->next) { NSDictionary *childDict = [self getNodeInfo:child]; if ([childDict count]) { [childArray addObject:childDict]; } } xmlFree(child); if ([childArray count]) [itemDict setObject:childArray forKey:@"child"]; [childArray release]; } return (NSDictionary *)itemDict; } 
/* xml */ - (NSDictionary *)xmlToDict { NSDictionary *resultDict = [NSDictionary dictionary]; if (self.content != nil) { xmlDocPtr doc = xmlParseMemory([self.content bytes], [self.content length]); if (!doc) { // NSLog(@"error"); } else { xmlNode *root = NULL; root = xmlDocGetRootElement(doc); resultDict = [NSDictionary dictionaryWithDictionary:[self getNodeInfo:root]]; xmlFree(root); } } return resultDict; } /* xml , */ -(NSDictionary *)getNodeInfo:(xmlNode *)node { NSMutableDictionary *itemDict = [[[NSMutableDictionary alloc] initWithCapacity:1] autorelease]; xmlChar *value = NULL; xmlAttr *attribute = NULL; if (node && node->name && ![[NSString stringWithCString:(char *)node->name encoding:NSUTF8StringEncoding] isEqualToString:@"text"]) { /* */ value = (xmlChar*)node->name; [itemDict setObject:[NSString stringWithCString:(char *)value encoding:NSUTF8StringEncoding] forKey:@"name"]; xmlFree(value); /* */ attribute = node->properties; NSMutableDictionary *attrDict = [[NSMutableDictionary alloc] initWithCapacity:1]; while(attribute && attribute->name && attribute->children) { value = xmlNodeListGetString(node->doc, attribute->children, 1); [attrDict setObject:[NSString stringWithCString:(char *)value encoding:NSUTF8StringEncoding] forKey:[NSString stringWithCString:(char *)attribute->name encoding:NSUTF8StringEncoding]]; xmlFree(value); attribute = attribute->next; } [itemDict setObject:attrDict forKey:@"attr"]; [attrDict release]; /* */ value = xmlNodeGetContent(node); [itemDict setObject:[NSString stringWithCString:(char*)value encoding:NSUTF8StringEncoding] forKey:@"value"]; xmlFree(value); /* */ NSMutableArray *childArray = [[NSMutableArray alloc] initWithCapacity:1]; xmlNode *child = NULL; for (child = node->children; child != NULL; child = child->next) { NSDictionary *childDict = [self getNodeInfo:child]; if ([childDict count]) { [childArray addObject:childDict]; } } xmlFree(child); if ([childArray count]) [itemDict setObject:childArray forKey:@"child"]; [childArray release]; } return (NSDictionary *)itemDict; }

My self.content stores xml, obtained from the Internet (from where it doesn't matter in principle) in NSData.
If there is no root element in xml, then the code will have to be redone a little, each element must be parsed into NSDictionary and “added” into NSArray, but with such a result structure, to put it mildly, it’s not convenient to work with the result.
I hope someone helped, and maybe from someone I will hear criticism and suggestions.
There is a problem, libxml gives insignificant faces, most likely the faces of the library itself.

')

Source: https://habr.com/ru/post/93168/


All Articles