通过删除额外/冗余格式标记来清理HTML

Azi*_*ziz 33 html php dom bbcode html-parsing

我一直在使用CKEditor wysiwyg编辑器建立一个网站,允许用户使用HTML编辑器添加一些注释.我最终在我的数据库中有一些非常冗余的嵌套HTML代码,这会减慢查看/编辑这些注释的速度.

我的评论看起来像这样(这是一个非常小的例子.我有超过100个嵌套标签的评论):

<p>
 <strong>
  <span style="font-size: 14px">
   <span style="color: #006400">
     <span style="font-size: 14px">
      <span style="font-size: 16px">
       <span style="color: #006400">
        <span style="font-size: 14px">
         <span style="font-size: 16px">
          <span style="color: #006400">This is a </span>
         </span>
        </span>
       </span>
      </span>
     </span>
    </span>
    <span style="color: #006400">
     <span style="font-size: 16px">
      <span style="color: #b22222">Test</span>
     </span>
    </span>
   </span>
  </span>
 </strong>
</p>
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  • 是否有任何库/代码/软件可以对HTML代码进行智能(即格式识别)清理,删除所有对格式没有影响的冗余标记(因为它们被内部标记覆盖)?我尝试了很多现有的在线解决方案(例如HTML Tidy).他们都没有做我想做的事.

  • 如果没有,我需要编写一些HTML解析和清理代码.我打算使用PHP Simple HTML DOM遍历HTML树并找到所有无效的标签.您是否建议任何其他更适合我的HTML解析器?

谢谢

.

更新:

我编写了一些代码来分析我的HTML代码.我拥有的所有HTML标签都是:

  • <span>用于font-size和/或的样式color
  • <font>与属性color和/或size
  • <a>用于链接(带href)
  • <strong>
  • <p> (单个标签包装整个评论)
  • <u>

我可以很容易地编写一些代码的HTML代码转换成设置高亮(例如[b],[color=blue],[size=3]等).所以我上面的HTML会变成这样的:

[b][size=14][color=#006400][size=14][size=16][color=#006400]
[size=14][size=16][color=#006400]This is a [/color][/size]
[/size][/color][/size][/size][color=#006400][size=16]
[color=#b22222]Test[/color][/size][/color][/color][/size][/b]
Run Code Online (Sandbox Code Playgroud)

现在的问题是:是否有一种简单的方法(算法/库/等)来清理将要生成的混乱(如原始HTML一样混乱)bbcode?

再次感谢

Bab*_*aba 20

介绍

到目前为止,最好的解决方案是使用HTML Tidy http://tidy.sourceforge.net/

除了转换文档格式之外,Tidy还可以通过使用clean选项自动将已弃用的HTML标记转换为其级联样式表(CSS)对应项.生成的输出包含内联样式声明.

它还确保HTML文档xhtml兼容

$code ='<p>
 <strong>
  <span style="font-size: 14px">
   <span style="color: #006400">
     <span style="font-size: 14px">
      <span style="font-size: 16px">
       <span style="color: #006400">
        <span style="font-size: 14px">
         <span style="font-size: 16px">
          <span style="color: #006400">This is a </span>
         </span>
        </span>
       </span>
      </span>
     </span>
    </span>
    <span style="color: #006400">
     <span style="font-size: 16px">
      <span style="color: #b22222">Test</span>
     </span>
    </span>
   </span>
  </span>
 </strong>
</p>';
Run Code Online (Sandbox Code Playgroud)

如果你跑

$clean = cleaning($code);
print($clean['body']);
Run Code Online (Sandbox Code Playgroud)

产量

<p>
    <strong>
        <span class="c3">
            <span class="c1">This is a</span> 
                <span class="c2">Test</span>
            </span>
        </strong>
</p>
Run Code Online (Sandbox Code Playgroud)

你可以得到CSS

$clean = cleaning($code);
print($clean['style']);
Run Code Online (Sandbox Code Playgroud)

产量

<style type="text/css">
    span.c3 {
        font-size: 14px
    }

    span.c2 {
        color: #006400;
        font-size: 16px
    }

    span.c1 {
        color: #006400;
        font-size: 14px
    }
</style>
Run Code Online (Sandbox Code Playgroud)

我们的完整HTML

$clean = cleaning($code);
print($clean['full']);
Run Code Online (Sandbox Code Playgroud)

产量

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title></title>
    <style type="text/css">
/*<![CDATA[*/
    span.c3 {font-size: 14px}
    span.c2 {color: #006400; font-size: 16px}
    span.c1 {color: #006400; font-size: 14px}
    /*]]>*/
    </style>
  </head>
  <body>
    <p>
      <strong><span class="c3"><span class="c1">This is a</span>
      <span class="c2">Test</span></span></strong>
    </p>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

使用的功能

function cleaning($string, $tidyConfig = null) {
    $out = array ();
    $config = array (
            'indent' => true,
            'show-body-only' => false,
            'clean' => true,
            'output-xhtml' => true,
            'preserve-entities' => true 
    );
    if ($tidyConfig == null) {
        $tidyConfig = &$config;
    }
    $tidy = new tidy ();
    $out ['full'] = $tidy->repairString ( $string, $tidyConfig, 'UTF8' );
    unset ( $tidy );
    unset ( $tidyConfig );
    $out ['body'] = preg_replace ( "/.*<body[^>]*>|<\/body>.*/si", "", $out ['full'] );
    $out ['style'] = '<style type="text/css">' . preg_replace ( "/.*<style[^>]*>|<\/style>.*/si", "", $out ['full'] ) . '</style>';
    return ($out);
}
Run Code Online (Sandbox Code Playgroud)

================================================

编辑1:脏黑客(不推荐)

================================================

根据你的上一条评论,它就像你想保留折旧风格.. HTML Tidy可能不允许你这样做,因为它,depreciated但你可以这样做

$out = cleaning ( $code );
$getStyle = new css2string ();
$getStyle->parseStr ( $out ['style'] );
$body = $out ['body'];
$search = array ();
$replace = array ();

foreach ( $getStyle->css as $key => $value ) {
    list ( $selector, $name ) = explode ( ".", $key );
    $search [] = "<$selector class=\"$name\">";
    $style = array ();
    foreach ( $value as $type => $att ) {
        $style [] = "$type:$att";
    }
    $replace [] = "<$selector style=\"" . implode ( ";", $style ) . ";\">";
}
Run Code Online (Sandbox Code Playgroud)

产量

<p>
  <strong>
      <span style="font-size:14px;">
        <span style="color:#006400;font-size:14px;">This is a</span>
        <span style="color:#006400;font-size:16px;">Test</span>
        </span>
  </strong>
</p>
Run Code Online (Sandbox Code Playgroud)

使用的类

//Credit : http://stackoverflow.com/a/8511837/1226894
class css2string {
var $css;

function parseStr($string) {
    preg_match_all ( '/(?ims)([a-z0-9, \s\.\:#_\-@]+)\{([^\}]*)\}/', $string, $arr );
    $this->css = array ();
    foreach ( $arr [0] as $i => $x ) {
        $selector = trim ( $arr [1] [$i] );
        $rules = explode ( ';', trim ( $arr [2] [$i] ) );
        $this->css [$selector] = array ();
        foreach ( $rules as $strRule ) {
            if (! empty ( $strRule )) {
                $rule = explode ( ":", $strRule );
                $this->css [$selector] [trim ( $rule [0] )] = trim ( $rule [1] );
            }
        }
    }
}

function arrayImplode($glue, $separator, $array) {
    if (! is_array ( $array ))
        return $array;
    $styleString = array ();
    foreach ( $array as $key => $val ) {
        if (is_array ( $val ))
            $val = implode ( ',', $val );
        $styleString [] = "{$key}{$glue}{$val}";

    }
    return implode ( $separator, $styleString );
}

function getSelector($selectorName) {
    return $this->arrayImplode ( ":", ";", $this->css [$selectorName] );
}

}
Run Code Online (Sandbox Code Playgroud)


Dun*_*zzz 5

您应该查看HTMLPurifier,它是一个很好的工具,用于解析HTML并从中删除不必要和不安全的内容.查看删除空跨配置和东西.配置我承认它可能是一个野兽,但这只是因为它是如此多才多艺.

它也很重,所以你想要保存数据库的输出(而不是从数据库中读取原始数据,然后每次使用净化器解析它.


MMe*_*eah 5

这是一个使用浏览器获取嵌套元素属性的解决方案.无需级联属性,因为css计算的样式已准备好从浏览器中读取.

这是一个例子:http://jsfiddle.net/mmeah/fUpe8/3/

var fixedCode = readNestProp($("#redo"));
$("#simp").html( fixedCode );

function readNestProp(el){
 var output = "";
 $(el).children().each( function(){
    if($(this).children().length==0){
        var _that=this;
        var _cssAttributeNames = ["font-size","color"];
        var _tag = $(_that).prop("nodeName").toLowerCase();
        var _text = $(_that).text();
        var _style = "";
        $.each(_cssAttributeNames, function(_index,_value){
            var css_value = $(_that).css(_value);
            if(typeof css_value!= "undefined"){
                _style += _value + ":";
                _style += css_value + ";";
            }
        });
        output += "<"+_tag+" style='"+_style+"'>"+_text+"</"+_tag+">";
    }else if(
        $(this).prop("nodeName").toLowerCase() !=
        $(this).find(">:first-child").prop("nodeName").toLowerCase()
    ){
        var _tag = $(this).prop("nodeName").toLowerCase();
        output += "<"+_tag+">" + readNestProp(this) + "</"+_tag+">";
    }else{
        output += readNestProp(this);
    };
 });
 return output;
}
Run Code Online (Sandbox Code Playgroud)

键入所有可能的css属性的更好解决方案,例如:
var _cssAttributeNames = ["font-size","color"];
是使用这里提到的解决方案: jQuery可以获得与元素相关的所有CSS样式吗?

  • 更新版本检测与嵌套子元素不同的父元素:http://jsfiddle.net/pLkwD/7/ (2认同)