В проекте для iPhone столкнулся с необходимостью парсинга большого количества xml ответов от сервера. Хотел бы поделиться своим решением парсинга XML в NSDictionary.
XML вида (должен присутствовать какой-то корневой элемент, в примере result):
будет преобразован в:
Собственно сами методы:
У меня в self.content хранится xml, полученный из интернета (откуда в принципе не важно) в NSData.
Если нет корневого элемента в xml, то код немного придется переделать, каждый элемент парсить в NSDictionary и «складывать» в NSArray, но при такой структуре результата, мягко говоря, с результатом работать не удобно.
Надеюсь, кому-то помог, а, возможно, от кого-то услышу критику и предложения.
Есть проблема, libxml дает незначительные лики, скорее всего лики самой библиотеки.
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 дает незначительные лики, скорее всего лики самой библиотеки.