xml,json都有大量的库来解析,我们如何解析html呢?

TFHpple是一个小型的封装,可以用来解析html,它是对libxml的封装,语法是xpath。
今天我看到一个直接用libxml来解析html,参看:http://www.cocoanetics.com/2011/09/taming-html-parsing-with-libxml-1/#comment-3090 那张图画得一目了然,很值得收藏。这个文章中的源码不能遍历所有的html,我做了一点修改可以将html遍历打印出来

// NSData data contains the document data 
// encoding is the NSStringEncoding of the data 
// baseURL the documents base URL, i.e. location

CFStringEncoding cfenc = CFStringConvertNSStringEncodingToEncoding(encoding); 
CFStringRef cfencstr = CFStringConvertEncodingToIANACharSetName(cfenc); 
const char *enc = CFStringGetCStringPtr(cfencstr, 0);

htmlDocPtr _htmlDocument = htmlReadDoc([data bytes], 
[[baseURL absoluteString] UTF8String], 
enc, 
XML_PARSE_NOERROR | XML_PARSE_NOWARNING); 
if (_htmlDocument) 

xmlFreeDoc(_htmlDocument); 
}

xmlNodePtr currentNode = (xmlNodePtr)_htmlDocument;

while (currentNode) 

// output node if it is an element

if (currentNode->type == XML_ELEMENT_NODE) 

NSMutableArray *attrArray = [NSMutableArray array];

for (xmlAttrPtr attrNode = currentNode->properties; attrNode; attrNode = attrNode->next) 

xmlNodePtr contents = attrNode->children;

[attrArray addObject:[NSString stringWithFormat:@"%s='%s'", attrNode->name, contents->content]]; 
}

NSString *attrString = [attrArray componentsJoinedByString:@" "];

if ([attrString length]) 

attrString = [@" " stringByAppendingString:attrString]; 
}

NSLog(@"<%s%@>", currentNode->name, attrString); 

else if (currentNode->type == XML_TEXT_NODE) 

//NSLog(@"%s", currentNode->content); 
NSLog(@"%@", [NSString stringWithCString:(const char *)currentNode->content encoding:NSUTF8StringEncoding]); 

else if (currentNode->type == XML_COMMENT_NODE) 

NSLog(@"/* %s */", currentNode->name); 
}

if (currentNode && currentNode->children) 

currentNode = currentNode->children; 

else if (currentNode && currentNode->next) 

currentNode = currentNode->next; 

else 

currentNode = currentNode->parent;

// close node 
if (currentNode && currentNode->type == XML_ELEMENT_NODE) 

NSLog(@"</%s>", currentNode->name); 
}

if (currentNode->next) 

currentNode = currentNode->next; 

else 

while(currentNode) 

currentNode = currentNode->parent; 
if (currentNode && currentNode->type == XML_ELEMENT_NODE) 

NSLog(@"</%s>", currentNode->name); 
if (strcmp((const char *)currentNode->name, "table") == 0) 

NSLog(@"over"); 

}

if (currentNode == nodes->nodeTab[0]) 

break; 
}

if (currentNode && currentNode->next) 

currentNode = currentNode->next; 
break; 



}

if (currentNode == nodes->nodeTab[0]) 

break; 

}

不过我还是喜欢用TFHpple,因为它很简单,也好用,但是它的功能不是很完完善。比如,不能获取children node,我就写了两个方法,一个是获取children node,一个是获取所有的contents. 还有node的属性content的key与node's content的key一样,都是@"nodeContent", 正确情况下属性的应是@"attributeContent",
所以我写了这个方法,同时修改node属性的content key.
NSDictionary *DictionaryForNode2(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) 

NSString *currentNodeContent = [NSString stringWithCString:(const char *)currentNode->content encoding:NSUTF8StringEncoding];

if (currentNode->type == XML_TEXT_NODE) 

if (currentNode->parent->type == XML_ELEMENT_NODE) 

[parentResult setObject:currentNodeContent forKey:@"nodeContent"]; 
return nil; 
}

if (currentNode->parent->type == XML_ATTRIBUTE_NODE) 

[parentResult 
setObject: 
[currentNodeContent 
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] 
forKey:@"attributeContent"]; 
return nil;



}

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 = DictionaryForNode2(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 = DictionaryForNode2(childNode, resultForNode); 
if (childDictionary) 

[childContentArray addObject:childDictionary]; 

childNode = childNode->next; 

if ([childContentArray count] > 0) 

[resultForNode setObject:childContentArray forKey:@"nodeChildArray"]; 

}

return resultForNode; 
}

TFHppleElement.m里加了两个key 常量
NSString * const TFHppleNodeAttributeContentKey = @"attributeContent"; 
NSString * const TFHppleNodeChildArrayKey = @"nodeChildArray";

并修改获取属性方法为:
- (NSDictionary *) attributes 

NSMutableDictionary * translatedAttributes = [NSMutableDictionary dictionary]; 
for (NSDictionary * attributeDict in [node objectForKey:TFHppleNodeAttributeArrayKey]) { 
[translatedAttributes setObject:[attributeDict objectForKey:TFHppleNodeAttributeContentKey] 
forKey:[attributeDict objectForKey:TFHppleNodeAttributeNameKey]]; 

return translatedAttributes; 
}

并添加获取children node 方法:
- (BOOL) hasChildren 

NSArray *childs = [node objectForKey: TFHppleNodeChildArrayKey];

if (childs) 

return YES; 
}

return NO; 
}

- (NSArray *) children 

if ([self hasChildren]) 
return [node objectForKey: TFHppleNodeChildArrayKey]; 
return nil; 
}

参看:http://giles-wang.blogspot.com/2011/08/iphoneansi.html

原文:http://blog.csdn.net/favormm/article/details/6794487

HTML 解析的更多相关文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  2. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  3. Html Agility Pack 解析Html

    Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面  用Fir ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  5. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  6. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  7. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  8. 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟内存泄漏say byebye

    一.写在前面 对于C++来说,内存泄漏就是new出来的对象没有delete,俗称野指针:而对于java来说,就是new出来的Object放在Heap上无法被GC回收:而这里就把我之前的一篇内存泄漏的总 ...

  9. SQL Server 数据加密功能解析

    SQL Server 数据加密功能解析 转载自: 腾云阁 https://www.qcloud.com/community/article/194 数据加密是数据库被破解.物理介质被盗.备份被窃取的最 ...

  10. .NetCore中的日志(1)日志组件解析

    .NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包 ...

随机推荐

  1. 基于jquery右侧悬浮加入购物车代码

    分享一款基于jquery右侧悬浮加入购物车代码.这是一款基于jQuery实现的仿天猫右侧悬浮加入购物车菜单代码. 在线预览   源码下载 实现的代码: <!--左侧产品parabola.js控制 ...

  2. 【WPF】MVVM前台绑定一组RadioButton按钮

    需求:制作一组RadioButton,像下面这样的效果: [MVVM]要显示一组RadioButton按钮,想法是Controller层联网获取到数据后,将数据进行处理,然后加到一个Observabl ...

  3. [uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  4. Android——ArrayList 、LinkList、List 区别 & 迭代器iterator的使用 & HashMap、Hashtable、LinkedHashMap、TreeMap

     ArrayList .LinkList.List 区别 & 迭代器iterator的使用 & HashMap.Hashtable.LinkedHashMap.TreeMap 一.几个 ...

  5. 网络配置br0 brtcl

    1.brctl addbr br0        如果根据第3步,那这里不用写 2.brctl addif br0 eth0    如果第3步写了,这里也不用 这时候用ssh应该会断网... 3.设置 ...

  6. 在JavaScript里写类层次结构?别那么做!

    从理论上讲,JavaScript并没有类.在实践中,下面的代码片段被广泛认为是JavaScript“类”的一个例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fu ...

  7. HBase系统入门--整体介绍

    转自:http://www.aboutyun.com/thread-8957-1-2.html 问题导读:1.HBase查询与写入哪个更好一些?2.HBase面对复杂操作能否实现?3.Region服务 ...

  8. thinkphp 第一个设计总结

    1.thinkphp的无限级分类不是万能的... 2.感觉先看前台(根据前台设计数据库)后写控制代码(后台),速度或许会快一点,思路明确...

  9. 关于Cocos2d-x项目运行的过程和场景切换步骤

    1.AppDelegate.cpp文件里面的applicationDidFinishLaunching函数其实可以看做C语言里面的main函数,是整个游戏运行的入口 这个函数里面的语句 auto sc ...

  10. python文件夹批处理操作

    如图所示,有一个test文件夹,里面有3个子文件夹,每个子文件夹中有若干图片文件    #场景1 读取一个文件夹中所有文件,存入到一个list表中 #coding:utf-8 from __futur ...