好(0) 差(0) 阅读(541) 评论(0)
前几天装了个lilina用来聚合(订阅)好友的Blog。很快发现这些聚合来的RSS其中的HTML代码很不规范,把声明为XHTML 1.0 Strict的页面破坏得不成样子。由于开头只是聚合了源自BlogCN的RSS,看看垃圾代码不算多,主要有<br />的不规范用法<br>和摘要对全文截断时会截断HTML标签,出现诸如“<b”(<br>被截断)、“&nbs”( 被截断)的东西;于是就写了段小程序三下五除二把垃圾代码摆平了。
谁知过了两天订了个源自MSN Space的RSS,发现垃圾代码超级多,img标签没有用“/>”结尾;用了一堆font标签、一堆border属性;height、width属性值画蛇添足加了个“px”;有很多空的span标签和div标签;有些属性值没有用引号引起来;url中的“&”没有用实体“&”代替。这么多垃圾可够麻烦的,起初让lilina把HTML标签都过滤掉(把“<”替换成“<”,“>”替换成“>”),结果页面非常难看。后来又想单独把lilina这页的文档类型DOCTYPE声明为HTML 4.01 Transitional,但是一想就算“&”在HTML 4.01中都是非法的,而且小区用的是模版,要改DOCTYPE可不是容易的事情。干脆一不做二不休,专门写一个函数用来清理垃圾代码,堪称一微型Tidy了(我当然知道PHP有Tidy的Extension啊,可是虚拟主机不会把这种东西编译进来啊)。下面就把我的微型Tidy贴一下:
function clean_summary($strSummary) {
// 把结尾错误截断的HTML标签去掉
$arrMatchings = array(
array("<", ">"),
array("&", ";")
);
foreach ($arrMatchings as $arrMatching) {
$intL = strrpos($strSummary, $arrMatching[0]);
if ($intL !== false) {
$intR = strrpos($strSummary, $arrMatching[1]);
if ($intL > $intR) $strSummary = substr($strSummary, 0, $intL);
}
}
// 为了效率,能用str_replace搞定的就不用正则表达式
$strSummary = str_replace(array(
"<br>", "<br/>", "</font>", "</span>"
), array(
"<br />", "<br />", "", ""
), $strSummary);
// 有些非得用正则表达式,顺便复习一下正则表达式的用法
$arrPatterns = array(
"#<script[.\s]*</script>#is",
"#<script.*/>#is",
"#<iframe[.\s]*</iframe>#is",
"#<iframe.*/>#is",
"#<img([^>]*)([^/])>#is",
'#(height|width)="?(\d+)(px)?"?#is',
"#border=[^\s]* #is",
"#<font[^>]*>#is",
"#<span[^>]*>#is",
"#<div[^>]*></div>#is",
"#<p[^>]*></p>#is"
);
$arrReplacements = array(
"", "", "", "",
"<img\1\2 />",
'\1="\2"',
"", "", "", "", ""
);
$strSummary = preg_replace($arrPatterns, $arrReplacements, $strSummary);
// 找出单独的“&”替换成“&”
$intAnd = -1;
while (($intAnd = strpos($strSummary, "&", $intAnd + 1)) !== false) {
if (($intSemicolon = strpos($strSummary, ";", $intAnd)) !== false) {
if ($intSemicolon - $intAnd > 6) {
$strSummary = substr_replace($strSummary, "&", $intAnd, 1);
continue;
}
$strEntity = substr($strSummary, $intAnd, $intSemicolon - $intAnd + 1);
$arrEntities = array(
" ", "&", "<", ">", """
);
$boolNotEscaped = true;
foreach ($arrEntities as $e) {
if ($strEntity == $e) {
$boolNotEscaped = false;
break;
}
}
if (!$boolNotEscaped) continue;
if (!preg_match("^&#\d+;\$", $strEntity)) {
$strSummary = substr_replace($strSummary, "&", $intAnd, 1);
}
} else $strSummary = substr_replace($strSummary, "&", $intAnd, 1);
}
return $strSummary;
}最后修改:Wen 于 2005-08-20 10:45:48
用户登录





