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;
}

ios 解析html的更多相关文章

  1. IOS 解析XML文档

    前段时间想找点事做,就是试着看能不能用豆瓣的API做点什么,于是就碰到了这个问题——XML解析. 老师还没讲,只能自己去查. XML文档解析主要有SAX和DOM两种模式,IOS上两种模式都可以用,这里 ...

  2. iOS解析crash日志:

    iOS解析crash日志:我们在ios开发中会碰到的很多crash问题,如果Debug调试模式的话,我们可以往往很容易的根据log的输出定位到导致crash的原因,但对于已经上线的应用,或者是rele ...

  3. iOS解析XML数据

    iOS中解析XML数据的类是  NSXMLParser,详细使用方法如下: 假设现在在内存中有XML的二进制数据对象(NSData):data(该数据可能来自网络,也可能是本地的文件数据),设置NSX ...

  4. iOS解析Server端返回JSON数据

    在做quhao APP架构时,后台Server端使用了Java,提供WebService,而iOS和Android作为移动客户端.在做数据交互时,Server端返回JSON格式数据.由于iOS SDK ...

  5. ios解析XML和json数据

    解析的基本概念所谓“解析”:从事先规定好的格式串中提取数据解析的前提:提前约定好格式.数据提供方按照格式提供数据.数据获取方按照格式获取数据iOS开发常见的解析:XML解析.JSON解析 一.XML数 ...

  6. IOS解析XML

    XML也许是我们储存数据和通讯数据中最常见的一种简易方式,当我们来到XML的海洋时,我们会发现当我们用iPhone程序解析XML时,我们是有如此多的选项,让人眼花缭乱.iOS SDK本身就带有两种不同 ...

  7. IOS 解析XML数据

    ●  什么是XML ●  全称是Extensible Markup Language,译作“可扩展标记语言” ●  跟JSON一样,也是常用的一种用于交互的数据格式 ●  一般也叫XML文档(XML ...

  8. IOS 解析Json数据(NSJSONSerialization)

    ● 什么是JSON ● JSON是一种轻量级的数据格式,一般用于数据交互 ● 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除 外) ● JSON的格式很像OC中的字典和数组 ...

  9. iOS解析数据时Error=3840

    1.解析JSon数据格式出错的问题 unescaped control character around character XXXX 和 The data couldn’t be read beca ...

  10. iOS解析JSON字符串报错Error Domain=NSCocoaErrorDomain Code=3840 "Invalid escape sequence around character 586."

    将服务器返回的JSON string转化成字典时报错: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid escape sequence ...

随机推荐

  1. centos7.0 没有netstat 命令问题

    centos有时安装时,没有安装netstat命令: 直接如下就可搞定: yum install wget 运行  yum install net-tools  就OK了 netstat常用命令: n ...

  2. Python 虚拟环境:Virtualenv

    安装sudo yum install python-virtualenv 使用方法 virtualenv [虚拟环境名称] 如,创建**ENV**的虚拟环境 virtualenv ENV 默认情况下, ...

  3. Hibernate之Criteria的完整用法

    Criteria的完整用法 QBE (Query By Example) Criteria cri = session.createCriteria(Student.class); cri.add(E ...

  4. Erlang 的新数据结构 map 浅析

    更新:文中示例代码直接从Joe的新版 Erlang 书中摘抄而来,其中模式匹配的代码有错误,现已纠正.应该用 := 匹配字段,而不是 => . 即将发布的 Erlang 17 最大变化之一包括新 ...

  5. linux配置文件的一些调优

    Linux中所有东西都是文件,一个socket就对应着一个文件描述符,因此系统配置的最大打开文件数以及单个进程能够打开的最大文件数就决定了socket的数目上限:但是linux是有文件句柄限制的,而且 ...

  6. windows 搭建 solr 5.3.2

    1. Tamcat 的安装,此不介绍 路径:F:\SolrTest\apache-tomcat-8.0.18 2. 解压 solr 5.3.2 路径:F:\Tool\solr-5.3.2 3. 复制s ...

  7. oracle的增删改查语句

    创建一个表: cteate table 表名(列1 类型, 列2 类型);查看表结构 desc表名添加一个字段 alter table 表名 add(列类型);修改字段类型 alter table 表 ...

  8. jQuery Validate 表单验证插件----利用jquery.metadata.js将校验规则直接写在class属性里面并定义错误信息的提示

    一.下载依赖包 网盘下载:https://yunpan.cn/cryvgGGAQ3DSW  访问密码 f224 二. 添加一个另外一个插件jquery.metadata.js 并把校验规则写在控件里面 ...

  9. excel if判断时间段早晚班

    =IF(OR(HOUR(B3)={9,10,11,12,13,14,15,16,17,18}),"早班","晚班")

  10. C++中对象初始化

    在C++中对象要在使用前初始化,永远在使用对象之前先将它初始化. 1.对于无任何成员的内置类型,必须手工完成此事. 例如: int x=0; double d; std::cin>>d; ...