锻造坊 - 检查您的 HTML

作者:Reuven M. Lerner

我们说蒂姆·伯纳斯-李发明了万维网,这当然是真的。但是,我们可以将 Web 归结为三项具体技术:URL(用于唯一标识互联网上的资源)、HTTP(用于传输文档的无状态协议)和 HTML(一种标记语言)。这些发明中的每一项都易于理解,也易于实现。正是这种简单性和优雅性的结合使 Web 取得了今天的成功。

这三项技术都随着时间的推移而发展,反映了新的用途和需求。例如,HTTP 现在支持请求和响应中的“标头”系统,该系统可以执行从指示响应正文的内容类型到提供有关数据应缓存多长时间的提示的所有操作。

HTML 也得到了很大的发展,演变成一种真正的语义标记语言(样式信息已移至外部 CSS 文档),并具有更严格和标准化的定义。标准化使 HTML 的编写稍微困难了一些,因为您需要更加注意项目,例如标签名称(保持小写)、属性(因为并非所有属性在所有上下文中都有效)和结束标签。这种标准化的一个优点是,我们现在可以更大程度地预测页面在不同浏览器中的外观。草率的 HTML 意味着浏览器必须决定您的意思,这可能会产生对其页面外观影响差异很大的后果。

更重要的是,AJAX 作为 Web 开发范例的兴起,使得 HTML 格式良好变得越来越重要。许多与 AJAX 相关的例程需要以某种方式修改页面上的特定元素。通常,最简单的方法是通过其 id 属性获取元素,该属性保证是唯一的。(如果您希望多个元素使用 ID,则实际上应该使用类代替。)在过去的几个月中,我处理了许多具有重复 ID 属性的页面。有时这是简单错误的结果,有时是 Web 设计师无知的结果。但在所有情况下,这都意味着我的 JavaScript 的执行方式与我预期的不同。

尽管 HTML 验证可能看起来很无聊,但它实际上是使 AJAX 驱动的、最新范例的、超级花哨的网站正常运行的重要组成部分。本月,我回顾一下我使用的一些工具,以确保我创建的 HTML 像往常一样符合标准。我首先介绍一些可以在单个页面上运行的简单手动测试。然后,我展示了一些在 Ruby on Rails 中开发应用程序时使用的自动化工具,这些工具使我可以批量检查所有页面的 HTML,包括那些需要密码保护才能访问的页面。

HTML 标准化

在继续之前,重要的是要认识到 HTML 是许多不同的、相关的标记语言的统称。并且,当我说标记时,我的意思是 HTML 是一种用于描述文本的语言,用于标识文本的不同部分。例如,一篇报纸文章将包含标题、一个或多个作者、一个或多个段落的文本、零个或多个照片以及每张照片的一个或多个标题。标记语言不会向文档添加内容,而是描述文档的各个部分,以便可以以适当的方式布局和显示它们。从这个意义上讲,HTML 是 SGML 的直接后裔,SGML 是一种多年前开发的标记语言,但使用起来要困难得多。

尽管多年来 HTML 有几个版本,但让我们关注当今最广泛使用的版本。也许最常见的 HTML 版本是非结构化、未版本化、非标准文档。我当然有创建许多此类文档的罪责,这些文档看起来像这样

<html>
<head>
    <title>This is the title</title>
</head>
<body>
    <h1>This is the headline</h1>
    <p>This is a paragraph</p>
    <p>This is another paragraph</p>
</body>
</html>

上述文档本身没有错。但是,由于它未能指示它正在使用的 HTML 版本,因此浏览器必须做出各种假设。这些假设可能会使预测不同浏览器的运行方式变得困难,使用一种称为怪异模式的东西。

幸运的是,我们可以选择标准实现,并通过在文档顶部添加 DOCTYPE 声明来向浏览器指示这一点。在分配 DOCTYPE 的值时,您需要决定是使用 HTML 还是 XHTML(即,XML 兼容版本的 HTML),以及您想要严格、过渡还是框架集类型的标记语言。

每种标记语言的严格版本是不允许任何样式元素的理想版本。在现代网站上,此类样式应在 CSS 中定义,而不是在 HTML 中定义。但是,某些站点可能难以遵守严格的定义,这可能是因为它们的创作工具使用了严格定义中不允许的标签,或者因为站点的作者想要使用禁止的元素,例如用于嵌入 Flash 的元素。为了使过渡到严格 HTML 更容易,标准允许过渡 HTML,它提供了更多的标签。

让我们将我们的小文档定义如下

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <title>This is the title</title>
</head>
<body>
    <h1>This is the headline</h1>
    <p>This is a paragraph</p>
    <p>This is another paragraph</p>
</body>
</html>

页面顶部的 <!DOCTYPE> 声明告诉浏览器(以及任何其他可能尝试解析页面的程序),我们想要遵循标准,但我们将使用过渡声明来执行此操作。

一旦我们表明我们愿意应用过渡标准,我们可能会发现我们的文档不再有效。例如,如果我在我的 HTML 文档中包含图像

<img src="/images/foo.jpeg">

将上面的行插入到我的文档中后,它不再有效,因为它缺少 alt 属性。一旦我添加了该属性,文档就有效了

<img src="/images/foo.jpeg" alt="foo">

但是,如果我们强制执行 XML 注意事项并将我们的文档声明为 XHTML 过渡,我们可以获得更好的结果。为此,我们不仅需要修改 !DOCTYPE 声明,还需要修改 <html> 标签

<!DOCTYPE html
          PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>This is the title</title>
  </head>
  <body>
    <h1>This is the headline</h1>
    <p>This is a paragraph</p>
    <p>This is another paragraph</p>
    <img src="/images/foo.jpeg" alt="foo">
  </body>
</html>

突然,我们的文档再次无效。因为我们已将其声明为 XHTML 过渡,所以我们需要遵循 XML 规则。我们需要关闭我们的 <img> 标签,最容易通过使用自闭合语法来完成

<!DOCTYPE html
          PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>This is the title</title>
  </head>
  <body>
    <h1>This is the headline</h1>
    <p>This is a paragraph</p>
    <p>This is another paragraph</p>
    <img src="/images/foo.jpeg" alt="foo" />
  </body>
</html>

有了这个,我们的文档现在是有效的。您可以想象,即使对于受过训练和经验丰富的人来说,找到文档中可能出现的所有问题也可能很困难。尝试检查站点上的所有页面,特别是包含数百或数千个页面的站点,显然是不可能的。

那么,解决方案是让程序自动检查页面的有效性,最好是作为自动化测试的一部分。这样,您可以快速轻松地发现何时出现问题。

W3C 验证器

检查页面标记有效性的最佳工具之一是万维网联盟的验证器,可在 validator.w3.org 上找到。我几乎完全从 Firefox 中使用验证器,我在其中安装了 Web Developer 插件。此插件允许您验证任何页面的 HTML,只需从浏览器中选择“验证 HTML”即可。浏览器将页面的 URL 提交给 W3C 验证器,然后 W3C 验证器会逐行指示页面包含哪些问题(如果有)。

但是,W3C 验证器至少有两个问题。首先,它要求您一次提交一个页面到验证器程序。这意味着花费大量时间和精力,只是为了检查您的页面。第二个考虑因素更实际;验证器仅适用于可通过互联网访问的页面,而无需密码保护。如果您的站点是在本地计算机上开发的,并且您有一个防火墙保护您的企业免受外部世界的侵害,您可能无法通过 Web 使用验证器。

解决此问题的一种方法是在本地计算机上安装 W3C 验证器。您可以从 validator.w3.org/source 获取源代码,该源代码以 Perl 程序的形式提供。在现代 Debian 和 Ubuntu 机器上,您可以安装 w3c-markup-validator,这使其可通过本地 Web 服务器使用,随时可以调用。

如果您最终手动安装验证器,则它需要许多模块,您可能需要从 CPAN(综合 Perl 存档网络)下载这些模块,CPAN 是包含开源 Perl 模块的大量镜像。可能需要一些试验和错误才能弄清楚哪些模块是必需的,但是如果您是 CPAN.pm 安装程序的经验丰富的用户,这应该不会太麻烦。请注意,SGML::Parser::OpenSP 模块需要 OpenSP 解析器,您可以从 SourceForge 上的 openjade.sf.net 获取它。

您可能已经知道,需要许多这些模块才能处理备用编码方案,特别是亚洲语言的编码方案。即使您不打算处理此类语言,这些模块也是强制性的,必须安装。

验证器程序(称为 check)应放在 CGI 程序的目录中,或放在由 mod_perl 处理的目录中,mod_perl 是 Apache 插件,可让您以更高的速度运行 Perl 程序以及其他功能。您还需要安装一个配置文件,通常放在目录 /etc/w3c 中,但您可以通过设置 W3C_VALIDATOR_CFG 环境变量来重新定位它。

验证 Rails 模板

现在您已在自己的服务器上安装了 W3C 检查器,您可以向其提供未向公众开放的 URL。但是,如果您正在 Ruby on Rails 中开发应用程序,则可以更进一步,将 W3C 验证器集成到您的自动化测试中。

为了做到这一点,您需要为 Rails 安装 html_test 插件。进入您的 Rails 应用程序的根目录,然后键入

script/plugin install 
 ↪http://htmltest.googlecode.com/svn/trunk/html_test

安装此插件后,您现在可以在功能和集成测试中使用三个新的断言:assert_w3c 如果 W3C 验证器批准您的 HTML,则返回 true;assert_tidy 如果您正在使用 HTML Tidy 库(如下所述),则返回 true;并且 assert_validates 调用这两个断言。

因此,如果您有一个要使用集成测试检查的 FAQ 页面,您可以编写如下内容

def test_faq
 get '/faq'
 assert_response :success
 assert_w3c
end

如果此页面的 HTML 获得 W3C 验证器的批准,则一切正常。如果此页面无效,您将获得大量输出,您应该将其重定向到一个文件。此文件不仅包含您的测试结果,还包含您从公共的、基于 Web 的 W3C 验证器获得的相同 HTML 输出。这意味着您将获得对您做错的事情的完整且易于阅读的描述。

您通常会发现,只需进行少量更正即可修复大量验证错误。例如,当我针对一个草率的 FAQ 页面运行此测试时,我得到了六个验证错误。我通过在我的 <html> 标签中指示适当的命名空间并从文件末尾删除一个多余的 </p>,就能够修复所有这些错误。

以这种方式检查 HTML 有效性既简单又容易。(但是,在每个页面上调用验证器可能很耗时;我认为这种权衡是值得的,但您可能不同意。)如果您始终要检查 HTML 有效性,则可以稍微更改测试环境的配置,以便它会自动发生,而无需每次都调用 assert_w3c。

为此,您需要修改 test_helper.rb,它位于 test 目录的顶部,并且包含在每个测试程序中。您所要做的就是添加

ApplicationController.validate_all = true
ApplicationController.validators = [:w3c]

您还可以检查 URL 和重定向的有效性;虽然这些本身不是检查 HTML 有效性,但它们确实随 html_test 插件一起提供,并且非常有用

ApplicationController.check_urls = true
ApplicationController.check_redirects = true

通过在您的 test_helper.rb 中添加这四行代码,您可以再次运行您的集成测试。如果任何验证测试失败,您可以查看 /tmp/w3c_last_response.html,其中将包含该失败的完整输出。但是,如果您有多个失败,这并没有太大帮助。

如果您使用 DRY(不要重复自己)原则设计了模板,那么修复 HTML 标记问题应该不会太糟糕。在许多情况下,您只需要更改布局中的一个标签即可修复所有问题。

HTML Tidy

W3C 验证器非常出色,但它并不总是能捕获所有内容,例如空标签。为此,您可能需要添加到您的武器库中,集成开源 Tidy 库,该库可以识别和修复编写不当的 HTML。Tidy 最初由 Dave Raggett 编写,他是 Web 早期最著名的开发人员之一;该项目现在位于 SourceForge 上的 tidy.sf.net

要将 Tidy 检查集成到您的 Rails 应用程序中,请首先从 SourceForge 安装该库。然后,安装用于 Tidy 集成的 Ruby gem

sudo gem install tidy

最后,下载并安装 Rails Tidy 插件

cd vendor/plugins
wget
http://www.cosinux.org/~dam/projects/rails-tidy/rails_tidy-0.3.tar.bz2
tar -jxvf rails_tidy-0.3.tar.bz2

现在,修改 test_helper 以读取

ApplicationController.validators = [:w3c, :tidy]

有了它,现在对您的服务器的每个请求都将由两个验证器而不是一个验证器检查。

Rails Tidy 插件除了检查和验证之外,还可以用于修复从您的服务器发送到用户浏览器的 HTML。尽管我从理论上喜欢这个想法,但解析和重写发送的每一点 HTML 似乎效率低下且速度缓慢。另外,我觉得在幕后神奇地重写 HTML 的情况下,调试 Web 应用程序(和 CSS)已经够困难的了。

结论

HTML 多年来发展了很多,手动处理使您的页面包含有效的 HTML 可能很困难。因此,使用自动化检查并将这些检查集成到 Web 应用程序的自动化设置中是确保您的站点尽可能紧密地遵守 HTML 标准的好方法。这不仅使您有最大的机会使站点在不同平台上呈现相似的效果,而且甚至可能提高您在 Google 中的排名(我曾在多个地方看到过这种说法,但我显然没有证据)。

如果您正在使用 Ruby on Rails,您可以从项目开始就轻松验证您的 HTML。这样做,您将在以后让自己的生活更轻松。此外,这比手动检查页面容易得多,并且可以确保即使是管理页面和其他隐藏页面也得到验证。

资源

Firefox 的 Web Developer 插件多年来一直是我的工作中不可估量的帮助,网址是 chrispederick.com/work/web-developer。它包含指向公共 W3C 验证器的链接,允许您检查浏览器当前正在查看的页面。

有效 HTML(和 XHTML)文档声明的一些示例位于 htmlhelp.com/tools/validator/doctype.html

W3C 验证器位于 validator.w3.org,验证器的源代码位于 validator.w3.org/source

Tidy 库的主页位于 tidy.sf.net。Ruby 的 Tidy gem 的主页是 rubyforge.org/projects/tidy。Rails Tidy 插件的主页位于 www.cosinux.org/~dam/projects/rails-tidy/doc

Ruby on Rails 的 html-test 插件位于 github.com/Empact/html_test/tree/master。Github 上的这个项目有一些文档,以及代码本身。

最后,Mike Clark 编辑并由 Pragmatic Programmers 出版的书《Advanced Rails Recipes》中,Peter Marklund 撰写了一个简短的配方(#57),描述了在 Rails 自动化测试中使用 HTML 验证。我通常发现这本书是灵感的绝佳来源,同时也让我了解了许多我尚未发现的插件和 gem。

Reuven M. Lerner 是一位长期从事 Web/数据库开发和咨询的顾问,他是西北大学学习科学专业的博士候选人,研究在线学习社区。在芝加哥地区生活四年后,他最近(与妻子和三个孩子)返回他们在以色列莫迪因的家。

加载 Disqus 评论