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. keepalived初探

    keepalived起初是为LVS设计的,专门用来监控LVS集群系统中各个real server的健康状况的,后来又在其中实现了VRRP协议,VRRP即virtual router redundanc ...

  2. Centos 下oracle 11g 安装部署及手动建库过程

    Oracle 11g 手动建库,在虚拟环境中,不使用DBCA工具进行创建数据库 1.Linux环境的基本配置 2.ip  10.11.30.60 3.Oracle 11g安装过程 ---------- ...

  3. 初次使用Docker的体验笔记

    一.前言 Docker容器已经发布许久,但作为一名程序员如今才开始接触,实在是罪过--        在此之前,我还没有对Docker进行过深入的了解,对它的认识仍停留在:这是一种新型的虚拟机.这样的 ...

  4. 堆栈 & Stack and Heap

    What's the difference between a stack and a heap? The differences between the stack and the heap can ...

  5. 初学嵌入式STM32基础下选哪款开发板适合学习

    iTOP-4412开发板 目前为止,在用户网盘上已经积累了多达100G以上资料, 这些资料都是和4412相关的,并不是随便拼凑起来的!同时我们也完全开放原厂资料. 鉴于用户对于海量资料无从下手的问题, ...

  6. #include <NOIP2008 Junior> 双栈排序 ——using namespace wxl;

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  7. 【Android 基础】Android中全屏或者取消标题栏

    先介绍去掉标题栏的方法: 第一种:也一般入门的时候经常使用的一种方法 requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏 注意这句一定要写在se ...

  8. 矩阵乘法快速幂 codevs 1250 Fibonacci数列

    codevs 1250 Fibonacci数列  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description 定义:f0=f1=1 ...

  9. 边工作边刷题:70天一遍leetcode: day 82

    Closest Binary Search Tree Value 要点: https://repl.it/CfhL/1 # Definition for a binary tree node. # c ...

  10. NUL 与 NULL

    NUL 与 NULL 在C语言中,字符串表示为字符的数组.字符串最后一个字符为空字符 ('\0'),官方将其定义为 NUL ,而 NULL 是一个宏,其定义如下: #define NULL ((voi ...