iOS之HTML字符串轉富文本

最近的項目中有圖文直播功能,這個功能需要把服務器返回的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的節(jié)點
OCGumboText the textual content of an elementDOM //節(jié)點的文本
OCGumboAttribute    an attribute of an Element object//DOM節(jié)點的屬性

轉換過程

首先創(chuàng)建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就能把這個富文本顯示出來

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末岩臣,一起剝皮案震驚了整個濱河市溜嗜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌架谎,老刑警劉巖炸宵,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谷扣,居然都是意外死亡土全,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門会涎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裹匙,“玉大人,你說我怎么就攤上這事末秃「乓常” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵练慕,是天一觀的道長。 經常有香客問我守问,道長隔显,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任哑梳,我火速辦了婚禮,結果婚禮上秃臣,老公的妹妹穿的比我還像新娘涧衙。我一直安慰自己,他們只是感情好奥此,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布弧哎。 她就那樣靜靜地躺著,像睡著了一般稚虎。 火紅的嫁衣襯著肌膚如雪撤嫩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天蠢终,我揣著相機與錄音序攘,去河邊找鬼。 笑死寻拂,一個胖子當著我的面吹牛程奠,可吹牛的內容都是我干的。 我是一名探鬼主播祭钉,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼瞄沙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了慌核?” 一聲冷哼從身側響起距境,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎垮卓,沒想到半個月后垫桂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡粟按,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年诬滩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钾怔。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡碱呼,死狀恐怖,靈堂內的尸體忽然破棺而出宗侦,到底是詐尸還是另有隱情愚臀,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布矾利,位于F島的核電站姑裂,受9級特大地震影響馋袜,放射性物質發(fā)生泄漏。R本人自食惡果不足惜舶斧,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一欣鳖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茴厉,春花似錦泽台、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嗜闻,卻和暖如春蜕依,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背琉雳。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工样眠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翠肘。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓檐束,卻偏偏與公主長得像,于是被迫代替她去往敵國和親束倍。 傳聞我的和親對象是個殘疾皇子厢塘,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內容