zoukankan      html  css  js  c++  java
  • iOS 解析 HTML

    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遍历打印出来

    001 // NSData data contains the document data 
    002 // encoding is the NSStringEncoding of the data 
    003 // baseURL the documents base URL, i.e. location  
    004     
    005 CFStringEncoding cfenc = CFStringConvertNSStringEncodingToEncoding(encoding); 
    006 CFStringRef cfencstr = CFStringConvertEncodingToIANACharSetName(cfenc); 
    007 const char*enc = CFStringGetCStringPtr(cfencstr, 0); 
    008     
    009 htmlDocPtr _htmlDocument = htmlReadDoc([data bytes], 
    010       [[baseURL absoluteString] UTF8String], 
    011       enc, 
    012       XML_PARSE_NOERROR | XML_PARSE_NOWARNING); 
    013 if(_htmlDocument) 
    014
    015    xmlFreeDoc(_htmlDocument); 
    016
    017    
    018 xmlNodePtr currentNode = (xmlNodePtr)_htmlDocument; 
    019    
    020 while(currentNode)  
    021     
    022         // output node if it is an element 
    023            
    024         if(currentNode->type == XML_ELEMENT_NODE) 
    025         
    026             NSMutableArray *attrArray = [NSMutableArray array]; 
    027                
    028             for(xmlAttrPtr attrNode = currentNode->properties; attrNode; attrNode = attrNode->next) 
    029             
    030                 xmlNodePtr contents = attrNode->children; 
    031                    
    032                 [attrArray addObject:[NSString stringWithFormat:@"%s='%s'", attrNode->name, contents->content]]; 
    033             
    034                
    035             NSString *attrString = [attrArray componentsJoinedByString:@" "];  
    036                
    037             if([attrString length]) 
    038             
    039                 attrString = [@" "stringByAppendingString:attrString]; 
    040             
    041                
    042             NSLog(@"<%s%@>", currentNode->name, attrString); 
    043         
    044         else if(currentNode->type == XML_TEXT_NODE) 
    045         
    046             //NSLog(@"%s", currentNode->content); 
    047             NSLog(@"%@", [NSString stringWithCString:(const char*)currentNode->content encoding:NSUTF8StringEncoding]); 
    048         
    049         else if(currentNode->type == XML_COMMENT_NODE) 
    050         
    051             NSLog(@"/* %s */", currentNode->name); 
    052         
    053        
    054            
    055         if(currentNode && currentNode->children) 
    056         
    057             currentNode = currentNode->children; 
    058         
    059         else if(currentNode && currentNode->next) 
    060         
    061             currentNode = currentNode->next; 
    062         
    063         else 
    064         
    065             currentNode = currentNode->parent; 
    066                
    067             // close node 
    068             if(currentNode && currentNode->type == XML_ELEMENT_NODE) 
    069             
    070                 NSLog(@"</%s>", currentNode->name); 
    071             
    072                
    073             if(currentNode->next) 
    074             
    075                 currentNode = currentNode->next; 
    076             
    077             else  
    078             
    079                 while(currentNode) 
    080                 
    081                     currentNode = currentNode->parent; 
    082                     if(currentNode && currentNode->type == XML_ELEMENT_NODE) 
    083                     
    084                         NSLog(@"</%s>", currentNode->name); 
    085                         if (strcmp((const char*)currentNode->name, "table") == 0) 
    086                         
    087                             NSLog(@"over"); 
    088                         
    089                     
    090                        
    091                     if(currentNode == nodes->nodeTab[0]) 
    092                     
    093                         break
    094                     
    095                        
    096                     if(currentNode && currentNode->next) 
    097                     
    098                         currentNode = currentNode->next; 
    099                         break
    100                     
    101                 
    102             
    103         
    104            
    105         if(currentNode == nodes->nodeTab[0]) 
    106         
    107             break
    108         
    109     }

    不过我还是喜欢用TFHpple,因为它很简单,也好用,但是它的功能不是很完完善。比如,不能获取children node,我就写了两个方法,一个是获取children node,一个是获取所有的contents.  还有node的属性content的key与node's content的key一样,都是@"nodeContent", 正确情况下属性的应是@"attributeContent",

    所以我写了这个方法,同时修改node属性的content key.

    01 NSDictionary *DictionaryForNode2(xmlNodePtr currentNode, NSMutableDictionary *parentResult) 
    02
    03     NSMutableDictionary *resultForNode = [NSMutableDictionary dictionary]; 
    04        
    05     if(currentNode->name) 
    06     
    07         NSString *currentNodeContent = 
    08         [NSString stringWithCString:(const char*)currentNode->name encoding:NSUTF8StringEncoding]; 
    09         [resultForNode setObject:currentNodeContent forKey:@"nodeName"]; 
    10     
    11        
    12     if(currentNode->content) 
    13     
    14         NSString *currentNodeContent = [NSString stringWithCString:(const char*)currentNode->content encoding:NSUTF8StringEncoding]; 
    15            
    16         if(currentNode->type == XML_TEXT_NODE) 
    17         
    18             if(currentNode->parent->type == XML_ELEMENT_NODE) 
    19             
    20                 [parentResult setObject:currentNodeContent forKey:@"nodeContent"]; 
    21                 returnnil; 
    22             
    23                
    24             if(currentNode->parent->type == XML_ATTRIBUTE_NODE) 
    25             
    26                 [parentResult 
    27                  setObject: 
    28                  [currentNodeContent 
    29                   stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] 
    30                  forKey:@"attributeContent"]; 
    31                 returnnil; 
    32    
    33             
    34         
    35     
    36        
    37    
    38        
    39     xmlAttr *attribute = currentNode->properties; 
    40     if(attribute) 
    41     
    42         NSMutableArray *attributeArray = [NSMutableArray array]; 
    43         while(attribute) 
    44         
    45             NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary]; 
    46             NSString *attributeName = 
    47             [NSString stringWithCString:(const char*)attribute->name encoding:NSUTF8StringEncoding]; 
    48             if(attributeName) 
    49             
    50                 [attributeDictionary setObject:attributeName forKey:@"attributeName"]; 
    51             
    52                
    53             if(attribute->children) 
    54             
    55                 NSDictionary *childDictionary = DictionaryForNode2(attribute->children, attributeDictionary); 
    56                 if(childDictionary) 
    57                 
    58                     [attributeDictionary setObject:childDictionary forKey:@"attributeContent"]; 
    59                 
    60             
    61                
    62             if([attributeDictionary count] > 0) 
    63             
    64                 [attributeArray addObject:attributeDictionary]; 
    65             
    66             attribute = attribute->next; 
    67         
    68            
    69         if([attributeArray count] > 0) 
    70         
    71             [resultForNode setObject:attributeArray forKey:@"nodeAttributeArray"]; 
    72         
    73     
    74        
    75     xmlNodePtr childNode = currentNode->children; 
    76     if(childNode) 
    77     
    78         NSMutableArray *childContentArray = [NSMutableArray array]; 
    79         while(childNode) 
    80         
    81             NSDictionary *childDictionary = DictionaryForNode2(childNode, resultForNode); 
    82             if(childDictionary) 
    83             
    84                 [childContentArray addObject:childDictionary]; 
    85             
    86             childNode = childNode->next; 
    87         
    88         if([childContentArray count] > 0) 
    89         
    90             [resultForNode setObject:childContentArray forKey:@"nodeChildArray"]; 
    91         
    92     
    93        
    94     returnresultForNode; 
    95 }

    TFHppleElement.m里加了两个key 常量

    1 NSString * constTFHppleNodeAttributeContentKey  = @"attributeContent"
    2 NSString * const TFHppleNodeChildArrayKey        = @"nodeChildArray";

    并修改获取属性方法为:

    1 - (NSDictionary *) attributes 
    2
    3   NSMutableDictionary * translatedAttributes = [NSMutableDictionary dictionary]; 
    4   for(NSDictionary * attributeDict in [node objectForKey:TFHppleNodeAttributeArrayKey]) { 
    5     [translatedAttributes setObject:[attributeDict objectForKey:TFHppleNodeAttributeContentKey] 
    6                              forKey:[attributeDict objectForKey:TFHppleNodeAttributeNameKey]]; 
    7   
    8   returntranslatedAttributes; 
    9 }

    并添加获取children node 方法:

    01 - (BOOL) hasChildren 
    02
    03     NSArray *childs = [node objectForKey: TFHppleNodeChildArrayKey]; 
    04        
    05     if(childs)  
    06     
    07         return YES; 
    08     
    09        
    10     return NO; 
    11
    12    
    13 - (NSArray *) children 
    14
    15     if([self hasChildren]) 
    16         return[node objectForKey: TFHppleNodeChildArrayKey]; 
    17     returnnil; 
    18 }

    最后我还加了一个获取所有content的主法:

    1 - (NSString *)contentsAt:(NSString *)xPathOrCss;

    请看 源码

  • 相关阅读:
    条码解析的一片js
    再看.net本质(二)
    再看.net本质
    powerdesigner逆向导出oracle数据库结构显示备注
    powerdesigner逆向工程,从数据库导出PDM
    实现HTTP跳转到HTTPS
    opencart 模块开发详解
    Opencart 之 Registry 类详解
    OpenCart 之registry功用
    php+支付宝整合
  • 原文地址:https://www.cnblogs.com/greywolf/p/2861636.html
Copyright © 2011-2022 走看看