Как стать автором
Обновить

Парсинг XML в NSDictionary при помощи libxml

Время на прочтение3 мин
Количество просмотров5.1K
В проекте для iPhone столкнулся с необходимостью парсинга большого количества xml ответов от сервера. Хотел бы поделиться своим решением парсинга XML в NSDictionary.

XML вида (должен присутствовать какой-то корневой элемент, в примере result):
<result success="true">
<item>Value</item>
<item attr="val" />
<item code="item">value</item>
</result>

будет преобразован в:
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"
    }
}


Собственно сами методы:
/* преобразование  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;
}


У меня в self.content хранится xml, полученный из интернета (откуда в принципе не важно) в NSData.
Если нет корневого элемента в xml, то код немного придется переделать, каждый элемент парсить в NSDictionary и «складывать» в NSArray, но при такой структуре результата, мягко говоря, с результатом работать не удобно.
Надеюсь, кому-то помог, а, возможно, от кого-то услышу критику и предложения.
Есть проблема, libxml дает незначительные лики, скорее всего лики самой библиотеки.
Теги:
Хабы:
+2
Комментарии10

Публикации

Истории

Работа

Swift разработчик
30 вакансий
iOS разработчик
22 вакансии

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн