本节书摘来自异步社区《重构HTML:改善Web应用的设计(修订版)》一书中的第2章,第2.5节,作者: 【美】Elliotte Rusty Harold 更多章节内容可以访问云栖社区“异步社区”公众号查看。
正则表达式对于独立的自定义的修改来说确实不错,但对于大量的修改来说难免乏味和困难。特别是,它们更大程度上是用来处理纯文本的,而不是处理半结构化的HTML文本的。为了批量改变和自动修复常见的错误,需要有能识别HTML标记的工具。第一个这样的工具是Dave Raggett的Tidy,它是一个原创的HTML修复器。Tidy作为一个简单的多平台的命令行工具,可以用来修正大量的HTML错误。
2.5.1 -asxhtml为了达到本书的目的,你需要使用-asxhtml命令行选项。例如,这个命令会把index.html转化成一个良构的XHTML并把结果保存到原文件上(-m选项的作用)。
$tidy –asxhtml –m index.html坦白地说,你有可能做出比在所有HTML文件上运行一遍Tidy就结束更糟糕的事,请不要停止继续往下阅读。Tidy的有些选项能够更好地改善代码,但也有处理不了或者处理不当的地方。比如,当在一个我至少5年没动过的页面上使用-asxhtml命令时,产生的错误信息如下所示:
line 1 column 1 - Warning: missing <!DOCTYPE> declaration line 7 column 1 - Warning: <body> attribute "bgcolor" has invalid value "#fffffff" line 16 column 2 - Warning: <table> lacks "summary" attribute line 230 column 1 - Warning: <table> lacks "summary" attribute line 14 column 91 - Warning: trimming empty <p> Info: Document content looks like XHTML 1.0 Transitional 5 warnings, 0 errors were found!这些问题Tidy通常处理不了。它本应该提供DOCTYPE,因为我指定了XHTML这个已知的DOCTYPE模式。它也不知道该如何处理 bgcolor="#fffffff" ,这个问题源于一个应当删除的多余的f,或者说整个bgcolor属性应该删掉并使用CSS替换。
提示
一旦发现了类似的问题,那么这个问题完全有可能出现在多个文档中。一个文件中出现的问题,就有必要在整个目录树中进行搜索和替换,不要放过任何一个可能出现的地方。多用代码的复制和粘贴,有些错误就只会出现一次。后面的两个问题是缺少summary属性的table。这是一个关于可访问性的问题,你应该修复它。Tidy实际上还会打印出更多的细节:
The table summary attribute should be used to describe the table structure. It is very helpful for people using non-visual browsers. The scope and headers attributes for table cells are useful for specifying which headers apply to each table cell, enabling non-visual browsers to provide a meaningful context for each cell. For further advice on how to make your pages accessible see http://www.w3.org/WAI/GL. You may also want to try "http://www.cast.org/bobby/" which is a free Web-based service for checking URLs for accessibility.表格摘要当然是好东西,并且你应该加上它。但Tidy本身不能帮你做摘要,你需要自己来。
最后一个警告信息是,Tidy发现一个空的段落元素而且将它抛弃。这个常见问题可能是骗人的,绝对需要再检查一遍。在这种情况下(你将看到的大部分情况也是如此),它指的是< p >标签被当做结束标签而不是起始标签来使用。就是说,像这样的标记:
Blah blah blah<P> Blah blah blah<P> Blah blah blah<P>Tidy看成了这样:
Blah blah blah <P>Blah blah blah</P> <P>Blah blah blah</P> <P></P>所以它把最后的空段落元素丢弃了。但几乎可以肯定的是,你需要的代码是这样的:
<P>Blah blah blah</P> <P>Blah blah blah</P> <P>Blah blah blah</P>这种问题很难搜索和替换,尽管XHTML严格的验证会至少警告你问题所发生的文件。你可以使用XSLT(稍后会讨论)来修正部分问题,但是问题不是太多的话,手工编辑这些文件会更安全,而且也不见得很繁重。
如果指定--enclose-text yes选项,Tidy会把所有未闭合的文本包裹到一个p元素中。比如:
$tidy –asxhtml --enclose-text yes example.htmlTidy还能提醒你其他一些需要手工修复的严重问题,包括:
属性值漏掉了右引号,如< p id="c1>;漏掉了闭合标签的>,如< p或 p ;拼错的元素和属性名,如把< table >写成了< tabel >。2.5.2 -clean另一个重要的选项是-clean。它把如i和font等废弃的表现性元素替换为CSS标记。比如当我在相同的文档上使用-clean时,Tidy为我的文档添加下面这些CSS规则:
<style type="text/css"> /*<![CDATA[*/ body { background-color: #fffffff; color: #000000; } p.c2 {text-align: center} h1.c1 {text-align: center} /*]]>*/ </style>同时也为之前使用了center的元素加上了必要的class属性。比如:
<h1 class="c1">Java Virtual Machines</h1>Tidy处理CSS只能做到这一步,但你还是可以重新审视这些文件,看是否能提取一个通用的外部文件供网站文档共享,而不是在每个单独的页面都引入这些CSS规则。更进一步说,你应该考虑使用一些语义更清楚的类名称取代Tidy那些多少有些平凡的默认名称。
比如,有时我使用i元素来指明我谈论而不是使用某个词,比如:
<p><i>May</i> can be very ambiguous in English, meaning might, can, or allowed, depending on context.</p>这里斜体并不表示强调,所以使用em来替换并不合适。相反应该替换为一个带class的span,像这样:
<p><span class='wordasword'>May</span> can be very ambiguous in English, meaning might, can, or allowed, depending on context.</p>接着,为样式表添加一条CSS规则,使它变为斜体样式:
span.wordasword { font-style: italic; }虽然Tidy不可能聪明到这个地步,它需要你的帮忙才行,但它终究是一个不错的开始。
2.5.3 编码令人吃惊的是,Tidy不善于检测HTML文档的字符集编码,尽管大部分HTML文档相对丰富的元数据都精确地指出了编码。如果你的内容不是ASCII或ISO-8859-1(Latin-1),你最好使用--input-encoding选项告诉Tidy文档的编码。比如要把文档保存为UTF-8编码,可以这样运行Tidy:
$tidy –asxhtml --input-encoding utf8 index.html不指定编码的话,Tidy默认生成的是ASCII文本。如果可以,它会把非ASCII字符转义为指定的实体符号,否则转为数字字符。虽然Tidy支持多种常见的编码,但我只推荐UTF-8。使用--output-encoding选项能实现这个目的:
$tidy –asxhtml --output-encoding utf8 index.html输入的编码可以跟输出的不一致。然而如果想要一致的编码,只需指定-utf8选项:
$tidy –asxhtml -utf8 index.html从多个方面综合考量,我强烈建议使用ASCII或UTF-8编码,因为其他编码不能保证文档在不同操作系统和语言环境下能够可靠地迁移。
2.5.4 整洁的格式Tidy当然还有很多不会对HTML本身产生修改的选项,它们能让文档看起来更整洁,从而使文本编辑器中代码的编辑更容易。
-i选项会缩进文本,这样就可以容易地看到元素的嵌套层次。Tidy足够聪明,不会缩进那些空白是有效的元素,比如pre元素。
-wrap选项会以指定的列数限制文本,通常80列左右比较合适:
$tidy –asxhtml -utf8 –i –wrap 80 index.html2.5.5 生成的代码Tidy对运行在PHP、JSP和ASP等技术上的页面的支持是有限的。基本上,它会忽略PHP、ASP或JSP部分中的内容,只能对剩下的HTML标记作处理。但这非常麻烦,特别是大部分的模板系统并不会注意元素边界。如果代码生成的是半个元素,或者只是一个起始标签,而又在最后使用文本标签来结束,就能把Tidy搞迷糊。我并不推荐直接在这些页面上使用Tidy。
相反,从网站上下载经过模板引擎处理的已经显示完毕的页面,在这些抽样页面上运行Tidy,然后把结果跟原有页面进行比较。通过观察区别所在,通常可以找出模板中需要修改的地方,然后手工完成这些修改。
虽然这不需要更多的手工劳动和脑力,但如果是由一个模板负责生成多个静态页面的话,比起大量静态HTML页面的半自动化处理来,这个过程更迅速。
2.5.6 当做库来用TidyLib是Tidy的C库版本,你可以将它集成到你的程序中。例如,这对编写处理整站的脚本来说是有用的。但从我个人角度看来,对于简单脚本来说C并不是很方便。我通常是编写shell或Perl脚本直接调用Tidy的命令行。
相关资源:JAVA上百实例源码以及开源项目