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. linux 中的进程wait()和waitpid函数,僵尸进程详解,以及利用这两个函数解决进程同步问题

    转载自:http://blog.sina.com.cn/s/blog_7776b9d3010144f9.html 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / wait ...

  2. pthread_testcancel和pthread_cancel函数的简单示例

    /*0.取消线程 int pthread_cancel(pthread_t thread); 设置取消点 void pthread_testcancel(void); 测试是否接收到取消请求,如果有, ...

  3. Java 并发编程学习笔记 理解CLH队列锁算法

    CLH算法实现 CLH队列中的结点QNode中含有一个locked字段,该字段若为true表示该线程需要获取锁,且不释放锁,为false表示线程释放了锁.结点之间是通过隐形的链表相连,之所以叫隐形的链 ...

  4. [LintCode]计算两个数的交集(一)

    问题分析: 既然返回值没有重复,我们不妨将结果放进set中,然后对两个set进行比较. 问题求解: public class Solution { /** * @param nums1 an inte ...

  5. node-webkit播放目录下所有网页文件

    1.编写index.html文件 这里我们需要播放某一个目录下所有的网页文件,要做到切换不同的网页,可以在index.html中使用iframe.通过js动态改变iframe的src属性,从而动态地切 ...

  6. JQuery下拉控件select的操作汇总

    JQuery获取和设置Select选项方法汇总如下: 获取select 先看看下面代码:   $("#select_id").change(function(){//code... ...

  7. 矩阵分解(Matrix Factorization)与推荐系统

    转自:http://www.tuicool.com/articles/RV3m6n 对于矩阵分解的梯度下降推导参考如下:

  8. 【转】WCF服务的创建和发布到IIS

    一. WCF服务的创建 有两种创建方式: 1.WCF服务库 2.WCF服务应用程序 如下图所示: 这里选择WCF服务库.注意事项: 1.WCF服务库是一个类库项目,这里选择.net 3.5版本(版本高 ...

  9. 【转】Microsoft .Net Remoting 之.Net Remoting基础篇

    .Net Remoting基础篇 一.Remoting基础 什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式.从微软的产品角度来看,可以说Remoting就是DCOM的一种升级, ...

  10. SyntaxError: inconsistent dedent

    错误原因: 一般是拷贝别人的代码过来编辑,由于编辑器不同,出现 tab和 space 的差别. 解决方法: Window->Preferences->PyDev->Editor-&g ...