最近的项目中有图文直播功能,这个功能需要把服务器返回的HTML字符串转为富文本NSAttributeString然后显示出来。然后这个HTML字符串是已经过服务器的处理,只留下<a>、<img>、<span>、<strong>这几个标签,这篇文章主要关注如何对上面的HTML进行parse然后生成对应的富文本
工具
OCGumob:
一款基于Google的Gumbo写的Objetive-C的HTML 文本解析器
用法:
OCGumboDocument *document = [[OCGumboDocument alloc] initWithHTMLString:htmlString];
OCGumboElement *root = document.rootElement;
//document: do something with the document.
//rootElement: do something with the html tree.
Class Description
OCGumboDocument the root of a document tree //类似DOM的根
OCGumboElement an element in an HTML document //OCGumboNode a single node in the document tree //DOM的节点
OCGumboText the textual content of an elementDOM //节点的文本
OCGumboAttribute an attribute of an Element object//DOM节点的属性
转换过程
首先创建OCGumboDocument
NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"];
NSString *htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
NSMutableAttributedString *attr = [NSMutableAttributedString new];
if (!error) {
NSLog(@"%@", htmlString);
OCGumboDocument *document = [[OCGumboDocument alloc] initWithHTMLString:htmlString];
OCGumboElement *body = document.body;
NSMutableDictionary *attributeDict = [NSMutableDictionary new];////空的字典,用来储存HTML中指定标签的内容
[self logNode:body dic:attributeDict content:attr];//对HTML文本进行解析
}
重点在于,首先初始化空的目标富文本NSMutableAttributeString,和空的属性字典NSMutableDictionary, 然后递归遍历OCGumboDocument中的OCGumboNode,判断每个Node是OCGumboText还是OCGumboElement,若是前者则抽取出来文本并使用属性字典的内容进行初始化并拼接到目标富文本上,若是后者则抽取出来想要的标签的属性并放到属性字典中待用
- (void)logNode:(OCGumboNode *)node dic:(NSMutableDictionary *)dic content:(NSMutableAttributedString *)content {
NSLog(@"childNode count %ld",node.childNodes.count);
NSMutableDictionary *copyDict = [dic mutableCopy];
for (int i = 0; i< node.childNodes.count; i++) {
OCGumboNode *child = node.childNodes[i];
if ([child isKindOfClass:[OCGumboText class]]) { //node为OCGumboText类型时候,它的nodeValue值就是HTML里面的普通文本
OCGumboText *test = (OCGumboText *)child;
if ([child.nodeName isEqualToString:@"#text"]) {
NSMutableAttributedString *subContent = [[NSMutableAttributedString alloc] initWithString:child.nodeValue attributes:@{NSForegroundColorAttributeName: [UIColor blackColor], NSFontAttributeName:[UIFont systemFontOfSize:15]}];//根据默认的颜色和字体生成普通的NSAttributeString
NSLog(@"========== textNode ===========");
NSLog(@" nodeName: %@, nodeValue:%@", child.nodeName, child.nodeValue);
NSLog(@"text: %@", test.data);
NSLog(@"========================== \n\n");
if (copyDict.count > 0) {
//对之前扫描到的属性字段进行遍历,并把属性设置到NSAtributeString上
[copyDict enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if ([key isEqualToString:@"color"]) {
[subContent addAttribute:NSForegroundColorAttributeName value:obj range:NSMakeRange(0, subContent.string.length)];
}
if ([key isEqualToString:@"strong"]) {
[subContent addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:20] range:NSMakeRange(0, subContent.string.length)];
}
}];
}
[content appendAttributedString:subContent];
}
}
if ([child isKindOfClass:[OCGumboElement class]]) { //判断是否是普通的node
NSArray *attributeArray = ((OCGumboElement *)child).attributes;
NSLog(@"************* attrbuteNode *************");
NSLog(@" nodeName: %@, nodeValue:%@", child.nodeName, child.nodeValue);
NSMutableDictionary *dic1 = [dic mutableCopy];
if ([child.nodeName isEqualToString:@"span"]) { //判断是否是span标签
for (OCGumboAttribute *attr in attributeArray) {
NSLog(@"name: %@, value: %@",attr.name,attr.value);
if ([attr.name isEqualToString:@"style"]) { //判断是否是style属性
if ([attr.value containsString:@"color"]) { //判断style属性中是否颜色,有则取出来
unsigned rgbValue;
NSScanner *scanner = [NSScanner scannerWithString:attr.value];
[scanner scanUpToString:@"color:#" intoString:NULL];
[scanner scanString:@"color:#" intoString:NULL];
[scanner scanHexInt:&rgbValue];
if (rgbValue > 0) {
UIColor *color = [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
dic1[@"color"] = color;
}
}
}
}
}
if ([child.nodeName isEqualToString:@"strong"]) { //判断是否是strong标签
dic1[@"strong"] = @(1);
}
if ([child.nodeName isEqualToString:@"img"]) { //判断是否img标签
for (OCGumboAttribute *attr in attributeArray) {
NSLog(@"name: %@, value: %@",attr.name,attr.value);
if ([attr.name isEqualToString:@"src"]) { //抽出img的src属性 并生成相应的NSAtributeString拼接上去
NSString *img = attr.value;
NSLog(@"img: %@",img);
NSAttributedString *imgstr = [[NSAttributedString alloc]initWithString:@"img" attributes:@{NSForegroundColorAttributeName: [UIColor blueColor],NSFontAttributeName:[UIFont systemFontOfSize:15]}];
[content appendAttributedString:imgstr];
}
}
}
NSLog(@"************************** \n\n");
NSLog(@"> > > > > > > > > > > > > > > \n\n");
[self logNode:child dic:dic1 content:content];
}
}
}
当对HTML解析完以后我们就拥有完整的NSAttributeString,这时候只要通过YYText就能把这个富文本显示出来