$content = <<<EOF<html><head><title>test</title></head> <body><p>error<br>another line</i></body></html>EOF;$tidy = new Tidy();$config = [ 'indent'=>true, 'output-xhtml'=>true,];$tidy->parseString($content, $config);$tidy->cleanRepair();echo $tidy, PHP_EOL;// <html xmlns="http://www.w3.org/1999/xhtml">// <head>// <title>// test// </title>// </head>// <body>// <p>// error<br />// another line// </p>// </body>// </html>
我们定义的 $content 中的这段 HTML 代码是没有任何格式的非常不规范的一段 HTML 代码。通过实例化一个 Tidy 工具之后,利用 parseString() 方法,并实行 cleanRepair() 方法之后,再直接打印 $tidy 工具,我们就得到了格式化之后的 HTML 代码。看起来是不是非常地规范,不管是 xmlns 还是 缩进 格式都非常标准。
parseString() 方法有两个参数,第一个参数便是须要格式化的字符串。第二个参数是格式化的配置,这个配置吸收的是一个数组,同时它内部的内容也必须是 Tidy 组件中所定义的那些配置信息。这些配置信息我们可以在文后的第二条链接中进行查询。这里我们只配置了两个内容, indent 表示是否运用缩进块级,output-xhtml 表示是否输出为 xhtml 。
cleanRepair() 方法用于对已解析的内容实行打消和修复的操作,实在也便是格式化的清理事情。

把稳我们在测试代码中是直接打印的 Tidy 工具,也便是说,这个工具实现了 __toString() ,而它真正的样子实在是这样的。
var_dump($tidy);// object(tidy)#1 (2) {// ["errorBuffer"]=>// string(112) "line 1 column 1 - Warning: missing <!DOCTYPE> declaration// line 1 column 70 - Warning: discarding unexpected </i>"// ["value"]=>// string(195) "<html xmlns="http://www.w3.org/1999/xhtml">// <head>// <title>// test// </title>// </head>// <body>// <p>// error<br />// another line// </p>// </body>// </html>"// }
各种属性信息获取
var_dump($tidy->isXml()); // bool(false)var_dump($tidy->isXhtml()); // bool(false)var_dump($tidy->getStatus()); // int(1)var_dump($tidy->getRelease()); // string(10) "2017/11/25"var_dump($tidy->getHtmlVer()); // int(500)
我们可以通过 Tidy 工具的属性获取一些关于待处理文档的信息,比如是否是 XML ,是否是 XHTML 内容。
getStatus() 返回的是 Tidy 工具的状态信息,当前这个 1 表示的是有警告或赞助功能缺点的信息,从上面打印的 Tidy 工具的内容我们就可以看出,在这个工具的 errorBuffer 属性中是有 warning 报警信息的。
getRelease() 返回的是当前 Tidy 组件的版本信息,也便是你在操作系统上安装的那个 tidy 组件的信息。getHtmlVer() 返回的是检测到的 HTML 版本,这里的 500 没有更多的解释和先容资料,不知道这个 500 是什么意思。
除了上面的这些内容之后,我们还可以得到前面 $config 中的配置信息及干系的解释。
var_dump($tidy->getOpt('indent')); // int(1)var_dump($tidy->getOptDoc('output-xhtml'));// string(489) "This option specifies if Tidy should generate pretty printed output, writing it as extensible HTML. <br/>This option causes Tidy to set the DOCTYPE and default namespace as appropriate to XHTML, and will use the corrected value in output regardless of other sources. <br/>For XHTML, entities can be written as named or numeric entities according to the setting of <code>numeric-entities</code>. <br/>The original case of tags and attributes will be preserved, regardless of other options. "
getOpt() 方法须要一个参数,也便是须要查询的 $config 中配置的信息内容,如果是查看我们没有在 $config 中配置的参数的话,那么返回就都是默认的配置值。getOptDoc() 非常知心,它返回的是关于某个参数的解释文档。
末了,是更加干货的一些方法,可以直接操作节点。
echo $tidy->head(), PHP_EOL;// <head>// <title>// test// </title>// </head>$body = $tidy->body();var_dump($body);// object(tidyNode)#2 (9) {// ["value"]=>// string(60) "<body>// <p>// error<br />// another line// </p>// </body>"// ["name"]=>// string(4) "body"// ["type"]=>// int(5)// ["line"]=>// int(1)// ["column"]=>// int(40)// ["proprietary"]=>// bool(false)// ["id"]=>// int(16)// ["attribute"]=>// NULL// ["child"]=>// array(1) {// [0]=>// object(tidyNode)#3 (9) {// ["value"]=>// string(37) "<p>// ………………// ………………echo $tidy->html(), PHP_EOL;// <html xmlns="http://www.w3.org/1999/xhtml">// <head>// <title>// test// </title>// </head>// <body>// <p>// error<br />// another line// </p>// </body>// </html>echo $tidy->root(), PHP_EOL;// <html xmlns="http://www.w3.org/1999/xhtml">// <head>// <title>// test// </title>// </head>// <body>// <p>// error<br />// another line// </p>// </body>// </html>
相信不须要过多地阐明就能够看出,head() 返回的便是 <head> 标签里面的内容,而 body() 、html() 也都是对应的干系标签,root() 返回的则是根结点的全部内容,可以看作是全体文档内容。
这些方法函数返回的内容实在都是一个 TidyNode 工具,这个我们在后面再详细地解释。
直接转换为字符串上面的操作代码我们都是基于 parseString() 这个方法。它没有返回值,或者说返回的只是一个 布尔 类型的成功失落败标识。如果我们须要获取格式化之后的内容,只能直接将工具当做字符串或者利用 root() 来得到所有的内容。实在,还有一个方法直接便是返回一个格式化后的字符串的。
$tidy = new Tidy();$repair = $tidy->repairString($content, $config);echo $repair, PHP_EOL;// <html xmlns="http://www.w3.org/1999/xhtml">// <head>// <title>// test// </title>// </head>// <body>// <p>// error<br />// another line// </p>// </body>// </html>
repairString() 方法的参数和 parseString() 是千篇一律的,唯一不同的便是它是返回的一个字符串,而不是在 Tidy 工具内部进行操作。
转换缺点信息在最开始的测试代码中,我们利用 var_dump() 打印 Tidy 工具时就看到了 errorBuffer 这个变量里是有缺点信息的。这回我们再来一个有更多问题的 HTML 代码片断。
$html = <<<HTML<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><p>paragraph</p>HTML;$tidy = new Tidy();$tidy->parseString($html);$tidy->cleanRepair();echo $tidy->errorBuffer, PHP_EOL;// line 4 column 1 - Warning: <p> isn't allowed in <head> elements// line 4 column 1 - Info: <head> previously mentioned// line 4 column 1 - Warning: inserting implicit <body>// line 4 column 1 - Warning: inserting missing 'title' element$tidy ->diagnose();echo $tidy->errorBuffer, PHP_EOL;// line 4 column 1 - Warning: <p> isn't allowed in <head> elements// line 4 column 1 - Info: <head> previously mentioned// line 4 column 1 - Warning: inserting implicit <body>// line 4 column 1 - Warning: inserting missing 'title' element// Info: Doctype given is "-//W3C//DTD XHTML 1.0 Strict//EN"// Info: Document content looks like XHTML 1.0 Strict// Tidy found 3 warnings and 0 errors!
在这段测试代码中,我们又利用了一个新的 diagnose() 方法,它的浸染是对文档进行诊断测试,并且在 errorBuffer 这个工具变量中添加有关文档的更多信息。
TidyNode 操作之前我们说到过,head()、html()、body()、root() 这几个方法返回的都是一个 TidyNode 工具,那么这个工具有什么分外的地方吗?
$html = <<<EOF<html><head><?php echo '<title>title</title>'; ?><# / JSTE code / alert('Hello World');#></head><body><?php // PHP code echo 'hello world!';?><% / ASP code / response.write("Hello World!")%><!-- Comments -->Hello World</body></html>Outside HTMLEOF;$tidy = new Tidy();$tidy->parseString($html);$tidyNode = $tidy->html();showNodes($tidyNode);function showNodes($node){ if($node->isComment()){ echo '========', PHP_EOL,'This is Comment Node :"', $node->value, '"', PHP_EOL; } if($node->isText()){ echo '--------', PHP_EOL,'This is Text Node :"', $node->value, '"', PHP_EOL; } if($node->isAsp()){ echo '++++++++', PHP_EOL,'This is Asp Script :"', $node->value, '"', PHP_EOL; } if($node->isHtml()){ echo '', PHP_EOL,'This is HTML Node :"', $node->value, '"', PHP_EOL; } if($node->isPhp()){ echo '########', PHP_EOL,'This is PHP Script :"', $node->value, '"', PHP_EOL; } if($node->isJste()){ echo '@@@@@@@@', PHP_EOL,'This is JSTE Script :"', $node->value, '"', PHP_EOL; } if($node->name){ // getParent() if($node->getParent()){ echo '&&&&&&&& ', $node->name ,' getParent is : ', $node->getParent()->name, PHP_EOL; } // hasSiblings echo '^^^^^^^^ ', $node->name, ' has siblings is : '; var_dump($node->hasSiblings()); echo PHP_EOL; } if($node->hasChildren()){ foreach($node->child as $child){ showNodes($child); } }}// ………………// ………………// // This is HTML Node :"<head>// <?php echo '<title>title</title>'; ><#// / JSTE code /// alert('Hello World');// #>// <title></title>// </head>// "// &&&&&&&& head getParent is : html// ^^^^^^^^ head has siblings is : bool(true)// ………………// ………………// ++++++++// This is Asp Script :"<%// / ASP code /// response.write("Hello World!")// %>" // ………………// ………………
这段代码详细的测试步骤和各个函数的阐明就不详细地逐一列举解释了。大家通过代码就可以看出来,我们的 TidyNode 工具可以判断各个节点的内容,比如是否还有子结点、是否有兄弟结点。工具结点内容,可以判断结点的格式,是否是注释、是否是文本、是否是 JS 代码、是否是 PHP 代码、是否是 ASP 代码之类的内容。不知道看到这里的你是什么觉得,反正我是以为这个玩意就非常故意思了,特殊是判断 PHP 代码这些的方法。
信息统计函数末了我们再来看一下 Tidy 扩展库中的一些统计函数。
$html = <<<EOF<p>test</i><bogustag>bogus</bogustag>EOF;$config = array('accessibility-check' => 3,'doctype'=>'bogus');$tidy = new Tidy();$tidy->parseString($html, $config);echo 'tidy access count: ', tidy_access_count($tidy), PHP_EOL;echo 'tidy config count: ', tidy_config_count($tidy), PHP_EOL;echo 'tidy error count: ', tidy_error_count($tidy), PHP_EOL;echo 'tidy warning count: ', tidy_warning_count($tidy), PHP_EOL;// tidy access count: 4// tidy config count: 2// tidy error count: 1// tidy warning count: 6
实在它们返回的这些数量都是一些缺点信息的数量。tidy_access_count() 表示的是碰着的赞助功能警告数量,tidy_config_count() 是配置信息缺点的数量,其余两个从名字就看出来了,也就不用我多说了。
总结总之,Tidy 扩展库又是一个不太常见但非常故意思的库。对付某些场景,比如模板开拓之类的功能来说还是有一些用武之地的。大家可以报着学习的心态好好再深入的理解一下,说不定它恰好就能办理你现在最棘手的问题哦!
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/01/source/8.一起学习PHP中的Tidy扩展库.php
参考文档:
https://www.php.net/manual/zh/book.tidy.php
http://tidy.sourceforge.net/docs/quickref.html