XHTMLの書き方と留意点

class="abstract" itemprop="http://purl.org/dc/terms/abstract"ひろく普及したHTMLの資産を生かしつつ、より強力で応用範囲の広いXMLの技術をWebに取り込むために、HTML 4.01と互換性を持つ新しいマークアップ言語XHTML 1.0が勧告されました。次の世代に備えるための、いくつかのポイントをご紹介します。

XHTMLとは

2000年1月26日にW3Cの勧告となったXHTML(Extensible HyperText Markup Language)[XHTML10]は、素朴な文書構造記述言語として発展してきた(あるいは混乱してきた)HTMLに、XML[XML1]の持つ柔軟性、拡張性を取り入れたものです。HTMLはSGMLの実装の一つで、書式にそれなりに自由度がありましたが、XHTMLはXMLの実装であるため、書式が厳密になっています(XMLは、SGMLの書法をシンプルで厳密なものにすることで、アプリケーションの開発や互換性をとりやすくした)。

また、HTMLは規格がどんどん拡張され、携帯端末などにとってはフルサポートするのが困難な規模となっています。一方、新しい規格であるMathMLやSVGが続々と登場し、これらを組み込んだ文書型を容易に定義できることも求められています。このため、利用環境に応じて必要な要素を選択して採用できるモジュール化や、他のXML文書との融合(拡張)などもXHTMLの目的のひとつです。これはXHTMLモジュール化仕様[XHTMLMOD]やXHTML Basic[XBASIC]で具現化されています。

XHTMLはXMLとして扱えるわけですから、XSLTで文書を変換するなど、さまざまな応用が可能です。特にXSLTを用いたメタデータの抽出は、誰もがセマンティック・ウェブに参加するための手段として注目すべきです。

XHTML 1.0

XHTML 1.0はXMLのルールに基づいて定義された言語であるとともに、HTMLの新バージョンでもあって、基本的には従来のHTML 4.01[HTML4]と同じ要素で構成されています。XMLとHTML双方のメリットを生かすことができる現実的な規格ですが、HTMLと互換性をとるためにはいくつかの注意が必要です。以下の注意点を守ることで、既存のHTMLブラウザでも、XMLエディタでも、きちんと表示され処理できるページを作ることができます。

XHTMLの基本形

整形式XML

XHTMLは、開始タグと終了タグがきちんとバランスし、要素が正しいツリーを形成する整形式であることが一番の基本です。タグを省略せず、大小文字を統一して記述したHTMLは、少しの修正だけで整形式XMLとすることができます。

  • 空要素タグを />で閉じる(留意点4
  • 属性値を全て引用符で囲み(留意点2)、属性名を省略した最小化を行わない(留意点7

基本的には、もとのHTMLが適切に書かれていればこれだけで整形式XMLとなるはずで、XSLTなどのツールを利用できるようになります。これがXHTMLの第一歩です(HTML4などのDTDには適合しなくなるので、この場合は文書型宣言は書きません)。

XML名前空間を宣言する

もっとも、整形式XMLにしただけでは、厳密にはHTMLともXHTMLとも言えない、自己流のXMLということになってしまいます。利用しているタグセットがXHTMLのものであることを示すためには、ルート要素(html要素)でXHTMLのXML名前空間を宣言しておきます。

(例) <html xmlns="http://www.w3.org/1999/xhtml">

XML対応ツールやブラウザは、これによって文書で用いられているタグセットがXHTMLのものであることを認識できます。多くの場合、文書をXHTMLとして標準的に(見出し、段落などの要素をそれらしく)レンダリングして表示してくれます。

適切な名前空間を宣言すれば、他のXML言語の語彙を組み込んでXHTML文書内で利用することも可能です。当サイトの「XHTMLを拡張し、メタデータを直接記述する」を参照してください(ただしこの場合、一般には次の厳密適合にはなりません)。

厳密適合のXHTML

XHTML文書をスキーマ(DTDなど)に対して検証したり、仕様書に厳密適合させる必要がある場合は、昔ながらの文書型宣言を置きます。また、一般にXML文書はXML宣言で始めることが推奨され、特に文字コードの扱いによってはこの宣言が必須になることがあります。これらを加えたXHTML1.0適合文書は、次のようなものです。

(例)

<?xml version="1.0" encoding="Shift_JIS"?>
<!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="ja" lang="ja">
  <head>
    <title>XHTMLの書き方と留意点</title>
  </head>
  <body>
    <p>XHTMLについて説明しましょう。</p>
  </body>
</html>

上の例は、次の「妥当な(Valid)XHTML文書」の要件に従って書かれています。

  1. 適切なDTDに従っていること
  2. 文書はhtmlをルート要素(root element=一番の親要素)として記述されていること
  3. このルート要素において、xmlns属性でXHTMLのXML名前空間を指定すること
  4. ルート要素の前に有効な文書型宣言を行っていること

スキーマに対して検証を行ったり厳密適合を求めたりする必要がなければ、4.の文書型宣言は特になくても構いません(その場合は、1.の適切なDTDというものも曖昧になってしまいますが)。単純に整形式にしてツールを利用するだけならば3.の名前空間も省略可能ですが、これでは広く認識されているX/HTMLを使うメリットもなくなってしまうので、これは記述しておく方が賢明です。

XML宣言は文字コードUTF-8もしくはUTF-16以外の(かつサーバーからの応答ヘッダなどで文字コードを示していない)場合は先頭に記述しなければなりません。

〔注意〕 旧版の仕様書の3.1.1にある文書型宣言のSYSTEM識別子は相対URIになっているため、そのままコピーして使うと落とし穴があります。第2版ではこれは絶対URIに改められ、A.1においてDTDのローカルコピーを使う場合の注意が追加されました。

HTMLとの互換性について

重要なのは、どんなタグの記法を用いれば、HTMLとの互換性を保ちつつXML(XHTML)としての機能を加えることができるのかということです。いくつかポイントを列挙します。

  1. 全てのタグ(要素タイプ名、属性名)は小文字で記述する

    HTMLでは大文字と小文字は区別されませんでしたが、XMLではこれを区別するため、IMGimgは別の要素タイプになってしまいます。XHTMLでは全ての要素タイプと属性は小文字で定義されたので、タグの記述にあたっても小文字を用いなければなりません(これまで書いたHTMLを書き直すのは大変…)。

    また、属性名だけでなく、method="post"等のように、属性値がDTDで選択肢が定義されているものは、その通り記述する必要があります。これらもみな小文字で定義されているので、「タグは小文字で書く」と考えておくのがよいでしょう。

  2. 属性の値は必ず引用符で囲む

    HTML(SGML)においては、値が数字など特定の値のみの場合は引用符を省略して width=100 のような記述が認められていましたが、XHTMLでは全ての属性値を引用符で囲んで width="100" のようにしなければなりません。

  3. 終了タグを省略しない

    HTML(SGML)ではDTDの定義によっては終了タグを省略することができました。たとえば、リスト項目要素のLIの場合、

    (誤りの例)

    <ul>
      <li>ある項目
    </ul>

    という具合に終了タグを省略することが認められ、それが一般的な書法となっていましたが、XMLではこれが認められません。必ず

    (正しい例)

    <ul>
      <li>ある項目</li>
    </ul>

    のように終了タグを加えなければなりません。内容モデルを持たない空要素を除いて、全ての要素は開始タグと終了タグのペアで記述します。

  4. 空要素のタグは />で閉じる

    また、HTMLのimg要素やbr要素のように、内容モデルを持たない空要素(HTMLでは開始タグしか使わないもの)は、XMLにおいては<br/>という具合に、タグを閉じるときに /> を使わなければなりません(空要素タグと呼ばれています)。ただし、この書式ではHTMLブラウザがタグを正しく認識できない可能性があるので、/ の前にスペースを置いて、 <br /> のように記述します。

  5. ファイル内の位置を示すにはid属性を併記する

    HTMLではファイル内の特定の位置へのリンクのためにname属性を使って

    (誤りの例)

    <a href="#foo">アンカーをクリックすると</a>
    ....
    <a name="foo">ここにジャンプする</a>

    という記述をしていましたが、XHTMLではファイル内部の位置を示す属性は id属性 になりました。従って、ジャンプ先は <a id="foo"> となるわけですが、このid属性をサポートしないブラウザもあるため、

    (正しい例)

    <a href="#foo">アンカーをクリックすると</a>
    ....
    <a name="foo" id="foo">ここにジャンプする</a>

    という具合に、name属性とid属性を同じ値で併記することが推奨されています(id属性そのものは、HTML 4.0から導入されています)。なお、XHTML1.1ではname属性は廃止され、id属性のみでフラグメントを示します。

  6. &はあらゆるところで&amp;と記述する

    HTMLでも普通&&amp;と記述することになっていますが、XHTMLの場合、その用法が徹底していて、たとえばCGIを呼び出すためのURLでも

    (誤りの例) <a href="/cgi-bin/myscript?name=kanzaki&score=100">

    ではなく

    (正しい例) <a href="/cgi-bin/myscript?name=kanzaki&amp;score=100">

    と記述する必要があります(本当はHTML 2.0の時からこの点も明記されていたが、ブラウザは&のままでもきちんと処理するように求められていたこともあり、これでも機能していた。cf. [RFC1866] 8.2.1. The form-urlencoded Media Type)。

  7. 属性の省略書式は使わない

    HTMLでは、属性の名前と値が同じ場合に、属性名を記述せずに

    (誤りの例) <input type="radio" name="bar" checked>

    としていましたが、XHTMLではこれは認められず

    (正しい例) <input type="radio" name="bar" checked="checked" />

    と書かなければなりません。こうすると古い(新しいものでも一部)ブラウザでは正しく働かないことがありますが、それに対する解決策は示されていないようです。

  8. head要素内のスクリプトやスタイルシートの注意

    HTMLとは異なり、XHTMLにおいてはスタイルやスクリプトも#PCDATA(字句解析を受けるデータ)として定義されたため、< はタグの開始と見なされ、コメントした内容は無視されることになります。たとえばJavascriptで数値の比較をするような式を記述していると、XHTMLではエラーになり、スタイルシートを古いブラウザから隠すために

    (誤りの例)

      <style type="text/css">
      <!--
        p {color:red}
      -->
      </style>

    のように記述していると、その定義は無視されてしまう可能性が高いとされています。解決策としては、外部ファイルにスタイルシートやスクリプトを記述することが推奨されています。

    XHTMLファイル内にスクリプト要素を記述するときは、不等号などが問題を生じないように、その内部をCDATAセクションとして宣言しておきます。ただし、CDATAの宣言をそのまま書くとスクリプトのエラーになるので、宣言を//でスクリプトのコメントにしておきます。

    (例)

    <script type="text/javascript">
    //<![CDATA[
    function dmmy(){
    //some script code
    }
    //]]>
    </script>
    

    このCDATAセクションの中に「HTMLのコメント宣言」に相当するものを書けば、XMLの処理には影響を与えませんが、古いブラウザがスクリプトのコードを表示しないようにする効果はあります。

  9. 言語コードの指定にxml:lang属性を用いる

    XMLでは言語コードの指定にxml:lang属性を用いるので、HTMLとの互換性のためにlang属性と合わせて記述します。

    (例) <p lang="fr" xml:lang="fr">Bonjour, monsieur</p>

    XHTML 1.1ではlang属性は廃止され、xml:lang属性のみを記述します。

厳密にはもう少し細かい話もあるので、詳しく知りたい場合はW3Cの勧告[XHTML10]を参照。

XML宣言とencoding

XHTML1.0の仕様書[XHTML10]3.1.1 Strictly Conforming DocumentsではXML宣言について次のように述べています:

XHTML document authors are strongly encouraged to use XML declarations in all their documents. Such a declaration is required when the character encoding of the document is other than the default UTF-8 or UTF-16 and no encoding was determined by a higher-level protocol.

旧版[XHTML10-1]の仕様書では and no encoding...以下の最後の部分がなかったため、「XHTMLでは文書の文字コードがUTF-8もしくはUTF-16でない場合はXML宣言が必須」といわれてきましたが、XHTML1.0 Second Edition[XHTML10-2]の仕様書C.9. Character Encodingでは

In order to portably present documents with specific character encodings, the best approach is to ensure that the web server provides the correct headers. If this is not possible, a document that wants to set its character encoding explicitly must include both the XML declaration an encoding declaration and a meta http-equiv statemen

と、サーバーのヘッダ情報を指定できない環境で文字コードを明示したい場合は、XML宣言とmeta要素の両方が必要であるとしています。ちなみにXMLの仕様書[XML1]では、4.3.3 Character Encoding in Entitiesにおいて次のように定められています:

In the absence of external character encoding information (such as MIME headers), parsed entities which are stored in an encoding other than UTF-8 or UTF-16 must begin with a text declaration (see 4.3.1 The Text Declaration) containing an encoding declaration...

つまり、HTTPヘッダなどで文字コード情報が送られない場合のみ、encoding宣言が必要だというわけです。

一部ブラウザとの互換性の問題点

Mac版のIE4.5はXML宣言を正しく理解できず、(おそらくデータをtext/plainとして扱って)ソースコードをそのまま表示してしまうという現象があります。文字コード情報をサーバー側で設定できるなら、XML宣言を省略するのが一番簡単です。

また、XSSI[SSI]の使える環境(Apacheのバージョン1.2以降は標準装備)なら、次のようにすることで比較的簡単にMacIE4.5のみXML宣言を出力しないようにすることが可能です。

(例)

<!--#if expr="$HTTP_USER_AGENT != /MSIE 4.5; Mac/" -->
<?xml version="1.0" encoding="Shift_JIS"?>
<!--#endif -->
<!DOCTYPE html
etc...

ここでは読みやすくするためにXSSI命令のあとで改行していますが、XML宣言の前に不正な改行が入ってしまうので、1,2行目は連続して記述する方がよいでしょう。

これらの対応が不可能な場合、ドキュメントの先頭に適当なコメントを置いておけば、Mac-IE4.5はデータがHTMLであると認識します。

(本来は正しくない例)

<!-- dummy comment -->
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html
   PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
etc...

これは厳密にはXMLの文法上誤りですが、実害は少ないので、Mac-IE4.5利用者にも表示できるようにするには一つの方法です。

Note: 〔補足〕Mac-IEの4.51ではこの状況は改善されて、基本的にはおかしなコメントなしでも正しく表示されるようですが、逆にディレクトリのデフォルトファイルとしてファイル名を省略して取得するときは、このコメントがあってもソースが表示されてしまいます。Mac-IE 5ではこれらの問題点は解消されています。

また、Windows版のIE5の場合は、コメントをXML宣言とhtml要素の間に置くと、文書をXMLとして解釈してしまいます。html要素の内部(開始タグ以降)であれば、問題なくHTMLとして解釈できるようです。

従来のHTMLをXHTMLに変換するための若干のヒント

新しく書くHTMLはこの基準に従うとして、これまで書いた(大量の)HTMLはどうすればいい? 上記のルールに従ってHTMLを書き換えるのは、ちょっと気が遠くなる作業です。

当サイトでは、いくつかのルールを組み合わせたperlスクリプトをつくって、全ページの書き換えを敢行しました。スクリプトだけでは完全に変換はできなくて、(特に昔書いたダーティなHTMLは)かなり手作業も必要でしたが、ゼロから始めるよりは遙かにスピーディにXHTML対応ページに生まれ変わらせることができました。

参考までに、そのなかからいくつかのルールをピックアップした簡単なスクリプト例を掲載しておきます。ある程度きちんとHTML4に準拠したページを作っていれば、このスクリプトでいい線まで行くのではないかと思います。

while(<>){
  s/<(\/)?([\w]+)/<$1\L$2/g;                #要素タイプ名を小文字に
  s/ (\w+)="/ \L$1="/g;                     #属性名を小文字に
  #空要素タグを /> で閉じる
  s/<(br|hr|img|link|input|col|base|meta|area|param)(.*?)>/<$1$2 \/>/g;
  s/<a name="(.*?)"/<a name="$1" id="$1"/g; #id属性を加える
  print;
}

*このスクリプトは参考として掲載しているもので、このままでは不完全、もしくは副作用をもつ可能性もあります。ご自分のHTML記述スタイルに合わせて変更の上ご利用ください。

また、タグの入れ子関係や終了タグ忘れ、空要素の「/>」忘れをチェックするには、こんなのも少しだけ役に立ちます。

while(<>){
  while(m|<(/)?(\w+).*?(/)?>|g){
    if($1){                             # 終了タグで
      if($2 eq $elmnt[$level]){         # 開始タグと対応すれば
        $level--;                       # 入れ子レベルを下げる
      }else{                            # でなければエラー
        print "Error at $.: $elmnt[$level] vs $2\n";
      }
    }else{                              # 開始タグで
      $elmnt[++$level] = $2 if(not $3); # 空要素でなければ
    }                                   # 入れ子レベルを上げる
  }
}

簡略化しているので、これをパスしたらそれでOKという訳には残念ながらいきません。しかし、すくなくともここでエラーがでたものはW3Cの検証サービス[VALIDATOR]でも確実に引っかかるので、事前チェック用にはなにがしかの使い途があるかも。

XML文書の構造とコメントの位置

XMLの仕様書[XML1]によれば、XML文書は次のように定義されています。

(仕様書の定義)

[1]   document   ::=   prolog element Misc*
[22]  prolog     ::=   XMLDecl? Misc* (doctypedecl Misc*)?
[23]  XMLDecl    ::=   '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
[27]  Misc       ::=   Comment | PI | S

つまり、XML文書は「プロローグ」というものから始まり、その「プロローグ」は(1)省略可能なXML宣言、(2)必要に応じてコメントなど、(3)省略可能な文書型宣言(およびコメントなど)、という順序で構成されます。この定義上、XML宣言を記述する場合は、それは必ず文書の先頭でなければならず、その前にコメントなどを記述することは文法違反です。XML宣言の後ならば、コメントは文法上はどこに記述しても構いません。

参照

[XHTML10]
[XHTML10-2]
Steven Pemberton, et al., XHTML 1.0: The Extensible HyperText Markup Language (Second Edition) - A Reformulation of HTML 4 in XML 1.0, , W3C Recommendation
<http://www.w3.org/TR/xhtml1/>
[XHTML10-1]
Steven Pemberton, et al., XHTML 1.0: The Extensible HyperText Markup Language - A Reformulation of HTML 4 in XML 1.0, , W3C Recommendation (obsoleted by 2nd edition)
<http://www.w3.org/TR/2000/REC-xhtml1-20000126>
[XHTMLMOD]
Murray et al., Modularization of XHTML, , W3C Recommendation
<http://www.w3.org/TR/xhtml-modularization>
[XHTML11]
Murray Altheim and Shane McCarron, XHTML 1.1 - Module-based XHTML, , W3C Recommendation
<http://www.w3.org/TR/xhtml11/>
[XBASIC]
Mark Baker, et al., XHTML Basic, , W3C Recommendation
<http://www.w3.org/TR/xhtml-basic/>
[XML]
Tim Bray, et al., Extensible Markup Language (XML) 1.0 (Second Edition), , W3C Recommendation
<http://www.w3.org/TR/REC-xml>
[HTML4]
Dave Raggett, et al., HTML 4.01 Specification, , W3C Recommendation
<http://www.w3.org/TR/html4>
[VALIDATOR]
Gerald Oskoboiny, W3C HTML Validation Service
<http://validator.w3.org/>
[RFC1866]
T. Berners-Lee and D. Connolly, Hypertext Markup Language - 2.0, , RFC 1866
<http://www.ietf.org/rfc/rfc1866.txt>
[SSI]
The Apache HTTP Server Project, Apache module mod_include, Apache server documentation
<http://httpd.apache.org/docs/mod/mod_include.html>