Refactoring HTML: Improving the Design of Existing Web Applications
Refactoring HTML: Well-Formedness
By Elliotte Rusty Harold
Validity, although important, is not nearly as crucial as wellformedness. There are often good reasons to compromise on validity. In fact, I often deliberately publish invalid pages. If I need an element the DTD doesn't allow, I put it in. It wont hurt anything because browsers ignore elements they don't understand. If I have a blockquote that contains raw text but no elements, no great harm is done. If I use an HTML 5 element such as
m that Opera recognizes and other browsers don't, those other browsers will just ignore it. However, if the page is malformed, the consequences are much more severe.
First, I wont be able to use any XML tools, such as XSLT or SAX, to process the page. Indeed, almost the only thing I can do with it is view it in a browser. It is very hard to do any reliable automated processing or testing with a malformed page.
What Is Well-Formedness?
Well-formedness is a concept that comes from XML. Technically, it means that a document adheres to certain rigid constraints, such as every start-tag has a matching end-tag, elements begin and end in the same parent element, and every entity reference is defined.
Classic HTML is based on SGML, which allows a lot more leeway than does XML. For example, in HTML and SGML, its perfectly OK to have a
<li> tag with no corresponding
</li> tags. However, this is no longer allowed in a well-formed document.
Well-formedness ensures that every conforming processor treats the document in the same way at a low level. For example, consider this malformed fragment:
The strong element begins in one paragraph and ends in the next. Different browsers can and do build different internal representations of this text. For example, Firefox and Safari fill in the missing start-and end-tags (including those between the paragraphs). In essence, they treat the preceding fragment as equivalent to this markup:
This creates the tree shown in Figure 3.1.
By contrast, Opera places the second p element inside the strong element which is inside the first
p element. In essence, the Opera DOM treats the fragment as equivalent to this markup:
By contrast, a well-formed document removes the ambiguity by requiring all the end-tags to be filled in and all the elements to have a single unique parent. Here is the well-formed markup corresponding to the preceding code:
This leaves no room for browser interpretation. All modern browsers build the same tree structure from this well-formed markup. They may still differ in which methods they provide in their respective DOMs and in other aspects of behavior, but at least they can agree on whats in the HTML document. Thats a huge step forward.
Most web sites will need to make at least some and possibly all of the following fixes to become well-formed.
In addition, namespace well-formedness requires that you add an
xmlns="http://www.w3.org/1999/xhtml" attribute to the root
Although its easy to find and fix some of these problems manually, youre unlikely to catch all of them without help. As discussed in the preceding chapter, you can use xmllint or other validators to check for well-formedness. For example:
TagSoup or Tidy can handle many of the necessary fixes automatically. However, they dont always guess right, so it pays to at least spot-check some of the problems manually before fixing them. Usually its simplest to fix as many broad classes of errors as possible. Then run xmllint again to see what you've missed.
The following sections discuss the mechanics and trade-offs of each of these changes as they usually apply in HTML.