zoukankan      html  css  js  c++  java
  • 不合规范的html段落php处理细则

    最近业余时间在维护一个rss聚合应用,就发现很多网站feed的条目摘要存在各种问题,用strip_tags一刀切吧,对摘要的段落和样式扭曲了

    例如:有一些网站的摘要是截断输出,例如指定的摘要长度截断,这样会导致摘要中出现非闭合的html标签,下面的摘要是一个例子:

    $str=<<<EOF
    <P>  【手机中国 导购】时间过得真快,转眼就我们就已经度过了2013年的上半年,而我们也悄无声息地老了半岁。不过随着时间的流逝,手机行业也在快速的进步着,其发展速度之快可以用日新月异来形容了。</P>
     <P align=center><IMG style="BORDER-BOTTOM: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-RIGHT: black 1px solid" alt="2.2GHz骁龙800四核 上半年热门机N宗最 " align=1 src="http://imgm.cnmo.com/cnmo_product/18_500x375/698/ceFYnyzZgUijQ.jpg"><BR>2012年的旗舰机型HTC Butterfly</P>
     <P>  回首2012年,手机市场还处于一个相对比较矛盾的时期,国产手机的初露锋芒以及国际大牌的推陈出新,让消费者有些摸不清头脑。到了2013年之后,虽然这个现象还存在着,唯一不同的就是消费者已经逐渐习惯了这个现状,整个手机行业也是在不断的向前进。</P>
     <P>  毫不夸张的说,今天刚刚上市了一款各个方面都表现突出的机皇级旗舰机,也许明天就被其他品牌旗舰所取代,这是一个不争的事实。但相比来说,每个品牌每款旗舰也都有自己的特长,比如处理器主频高或是屏幕尺寸大等等。</P>
     <P align=center><IMG style="BORDER-BOTTOM: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-RIGHT: black 1px solid" alt="6.44英寸屏骁龙800 上半年热门机N宗最 " src="http://img.cnmo-img.com.cn/905/904155.jpg"></P>
     <P>  俗话说风水轮流转,曾经榜上有名的强机也许今天就名落孙山,物竞天择,适者生存这句话说的不无道理。今天笔者也给大家统计了2013上半年最新智能手机N宗最,下面就让我们一起看一下吧。<STRONG>
    EOF;


    上面的摘要有几点不合法:
    1.html标签大写
    2.最后一个strong由于截断没有正常闭合,strong的父标签p丢失
    3.标签的属性中出现了一些样式属性和定义,像:align,style

    下面说一说它们的影响
    2:如果不加处理的输出会造成页面样式混乱,像非正常闭合的strong浏览器会自动把它后面的输出算成它的子元素.
    3:样式定义可能影响你的页面样式,图片溢出你的摘要容器
    1:不会造成视觉上的错误,但它会影响你的html合法性

    下面来说说处理方法
    3:可以用正则把属性给替换掉,像

    preg_replace("/<([a-z][a-z0-9]*)(?:[^>]*(ssrc=['"][^'"]*['"]))?[^>]*?(/?)>/i",'<$1$2$3>',$str);


    2:可以用DOMNode::C14N方法来规范,它可以把丢失的标签给补上,只不过<img />会变成<img></img>

    等等:
    1.为什么不用strip_tags来处理呢?
    是可以,虽然它也可以保留指定的标签,但我会把哪些不安全的标签交给htmlentities

    2.好像dom可以删除属性吧!
    对,这是下面要讲的,综合处理1,2,3的代码如下

    $doc = new DOMDocument();
    $doc->formatOutput=false;
    
    $doc->loadHTML(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8'));
    $nodes = $doc->getElementsByTagName('*');
    foreach ( $nodes as $node ) {
    	$delAtts=array();
    	//找到节点的所有属性
    	$nodeN=$node->tagName;
    	$nodeAtts=$node->attributes;
    	foreach($nodeAtts as $attN=>$att){
    		//是img保留src属性
    		if(strtolower($attN)=='src' && strtolower($nodeN)=='img') continue;
    		//不是直接删除所有属性
    		array_push($delAtts,$attN);
    	}
    	foreach($delAtts as $A){
    		$node->removeAttribute($A);
    	}
    }
    $doc->saveHTML();
    $pstr=$doc->GetElementsByTagName('body')->item(0)->C14N();
    //clear empty tag
    $pstr=preg_replace('/<(w+)>(s| )*</1>/i',"",$pstr);


    大体上已经OK了,$pstr的内容是body包裹的$str,最后只需要把body解决掉就可以.
    最后要说的有几点:
    1.一定不要在遍历属性时把它删除,例如:img有三个属性style,src,alt,它只会删除掉style,style后面的并不会删除
    2.一定不要用saveHTML()的返回值作为后续处理的内容,后果是汉字变成如下的东东:

    &#12288;&#12288;&#22238;&#39318;2012&#24180;&#65292;&#25163;&#26426;&#24066;&#22330;&#36824

    也不要怕,只需要再调一次

    mb_convert_encoding($str, 'UTF-8','HTML-ENTITIES')


    就ok了,为了偷懒,所以它的返回值不要用

    3.$doc->GetElementsByTagName('body')->item(0)->C14N();


    也可以换成:

    $doc->documentElement->C14N();


    只不过返回值不光有body还有html标签,不在乎的话也可以用它,毕竟比GetElementsByTagName更省事

  • 相关阅读:
    poj3417 闇の連鎖 【树上差分】By cellur925
    Luogu P1613跑路【倍增】By cellur925
    CF519E A and B and Lecture Rooms
    poj 2412 The Balance 【exgcd】By cellur925
    NOIp 2014 解方程 【数学/秦九韶算法/大数取膜】By cellur925
    Maven项目整合SSH框架
    传递依赖
    Maven项目整合Struts2框架
    K.O. -------- Eclipse中Maven的报错处理
    依赖范围
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3174430.html
Copyright © 2011-2022 走看看