The markup, as originally posted, makes a valid XHTML 1.0 Transitional document if the XHTML 1.0 Transitional document type declaration is added at the start.
As edited by @adamjansch, with the XHTML 1.0 Strict document type declaration, it is not valid, and presumably it was validated using that document type declaration. Then the first error message is “character data is not allowed here” with some explanations of possible causes, including “putting text directly in the body of the document without wrapping it in a container element (such as a <p>aragraph</p>)”. This gets close: the problem is that in XHTML 1.0 Strict, a form element may have block-level children only.
This means that any text and text-level markup like input must be wrapped in one or more block containers, such as p, div, fieldset, or table. Of these, div is the only neutral one, with no default impact on rendering:
<!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" xml:lang="en" lang="en"> <head> <title>this is the title of the web page</title> </head> <body> <form action="formscript.php" method="post"> <div> first name:<input type="text" name="firstname" /> <input type="submit" /> </div> </form> </body> </html>