パスワードを忘れた? アカウント作成
220021 journal

Torisugariの日記: HTMLのtitle要素とtitle属性 2

日記 by Torisugari

結論から言うと、HTMLのtitle要素は失敗で、最初から全てtitle属性にしておけば良かった、と私は思っています。ただ、title要素が要素であることにもきちんとメリットはありますし、互換性を考えると今さらどうしようもないことではありますが、まあ、こういう意見もある、ということでひとつ。

HTMLは既に1.0の時から、title要素とtilte属性の役割を区別していました。title要素は書かれている文書のタイトルで、title属性はリンク先の文書のタイトルです。現在のtitle属性はリンク先に限りませんから、少し用途が広くなっているものの、基本的な用途は概ね同じと言えるでしょう。後知恵ですが、これは、そもそも、分ける必要がなかったと思います。どちらも親ノードの表題ですから、何を指しているのか、少なくともパーサーにとっては自明です。

(SGMLの)属性は要素に比べて少し窮屈な機能です。属性の内容(属性値)はマークアップされていない素のテキストに限られますし、兄弟ノードに同じ名前(属性名)の属性を持つことも許されません。さらに、属性自身が複数の子ノードを持つことはできません。

  1. 内容はテキストだけ
  2. 兄弟で重複禁止
  3. 子供なし

他方で、要素にはこれら3つの制限は存在しない上に、属性にできて要素にできないこともありません。つまり、現在要素で定義されているような機能を属性で定義しなおすことは出来ませんが、逆に属性で定義されている機能を要素で定義しなおすことのできる上位互換なのです。
例えば、

<a href="www.example.com">Hello, world!</a>

の代わりに

<a>
  <href>www.example.com</href>
  <value>Hello, world!</value>
</a>

のようなタグをつけても、まあ、それはそれでうまくいっていたはずです。文字数が気になるなら終了タグを暗黙にして、

<a>
  <href>www.example.com
  <value>Hello, world!
</a>

としておけば、マークアップの使い勝手はさほど変わらなかったでしょう。HTMLは「テキストノードをなるべく描画する」という縛りを入れているので、"www.example.com"をテキストノードとしてユーザーに晒したくない場合はそれには違反してしまいますが、それはスタイルのポリシーですから、まあ、言ってしまえばどうとでもなることです。仕様策定者にとって、要素は属性より便利なのです。

しかし、DOMを使う側から考えるとこの評価は逆転します。試しに、先ほどのアンカーからhref属性・要素の内容を取得してみると良く分かります。

まず、属性の場合は次のようになります。

var hyperLinkURI = anchorElement.getAttribute("href");

次に、要素の場合はこうです。

var hrefElements = anchorElement.getElementsByTagName("href");
var hrefElement = hrefElements[0];
var hrefNode = hrefElement.firstChild;
var hyperLinkURI = hrefNode.nodeValue;

この程度のスクリプトに4行も使うことはないかもしれませんが、気の利いたエラー処理を行おうと思ったら区切りは必要です。href要素を書き落としていたり、hrefの中身が空だったり、hrefの子がテキストノードではなかったりする可能性もあるわけですから。しかし、このスクリプトで最も問題なのは"0"や"firstChild"といった決め打ちを行わざるを得ない点で、これは仕様の罪です。

まあ、DOM L3を使えば、スクリプトの量自体は半分に減らせますし、DOM HTMLで丁寧にラッピングしておけば(例えば、element.hrefといったプロパティを定義しておくと)、スクリプトを書く手間はさほど問題になりません。が、筋が悪いことには変わりありませんから、反省も込めて理由を検討しておきましょう。

DOM APIのgetElementsByTagNameは、子ノードをNodeList、つまり配列で返します。これは当たり前のことですが、非常に重要なことです。hrefを文字列として取得したい場合、DOMの利用者は、要素そのものを直接渡して欲しいと思っているはずです。ここで、配列を渡されるのは、同名の子要素が複数あることをAPIが想定しているからです。同名兄弟の存在を否定されている属性ではありえません。また、firstChildを指定しなければならないのは、複数の子を持っているかもしれないからです。これも属性ではありえません。nodeValueを……、属性値はテキスト表現に収まりますから、これもありえません。

DOM APIは、DTDという空気を読まずに自分の流儀を押しつけてきますが、逆に言うと、DTDで細かく制御された要素は、要素の本来的な姿を歪めてルールを押し付けていることになり、DOM APIのような一貫性を欠いているのです。結果として、href要素の流儀には「間違えた記法」が数多く存在することになり、それがエラー処理の多さに繋がっています。おそらく、この割りをもっとも喰っているのは、文書を書く人間です。DTDに「あれは禁止、これも禁止」と書かれているため、要素の使い方が直観的にわかりにくく、教育にコストが転化されているはずですから。

人間はあまりにもソフトなソフトウェアなので、普段こういうことは意識しませんが、DOM APIのように愚直な物差しを当てると不合理が浮かび上がってきます。属性の3つの制限は、自由を求める時には邪魔ですが、制限つきで問題ない場合は、制限されている方が曖昧さが減ってむしろ楽なのです。

さて、href属性の素晴らしさを再確認したところで、title要素に話を戻しましょう。title要素は中身がテキストでなければいけません。title要素は文書につき1つです。title要素はhead要素の子要素でなければいけません……

そこまで制限を付けるなら、最初からhead要素の属性にしておいてくれたら話が早かったのに、と思いませんか?一応、title要素はlang属性を設定できることになっていますが、実用性皆無の上、(xhtmlのように)文書内のtitle属性にもlangが設定できないと対象性が保てないので、どのみちtitle属性で事足りるはずなのです。

更に問題なのは、HTMLのtitle要素が他へ及ぼした影響力です。ざっと思いつくXMLベースの規格だけでも、XBELA9.com OpenSearchDocBookと枚挙に暇がありません。おそらく、私のようなことを考えている人はあまりいないのでしょう。その点、SVGはtitle要素の内容にマークアップを許しているので、納得がいくんですけどね。まあ、XULみたいに、場当たり的(失礼)に設計されていても、なぜか属性になっている規格もあるのですが。

例えば、

The "ShortName" element

Contains a brief human-readable title that identifies this search engine.

  • Parent: OpenSearchDescription
  • Restrictions: The value must contain 16 or fewer characters of plain text. The value must not contain HTML or other markup.
  • Requirements: This element must appear exactly once.

Example:

<ShortName>Web Search</ShortName>

と、書いてあるのを見ると、何か、こう、こみ上げてくるものがあります。

まとめると、属性の方が制限が厳しいので、どちらでもよい場合は「属性」を選択すると"lean and mean"になります。それを覆すのは、もう、好みとか、拘りとか、惰性とか、とにかく理屈ではない何かだと思うのですが、ほとんどの仕様はその辺に無頓着です。

もっとも、(私を含めて)マークアップ言語のサブセットを設計する予定がない人には、どうでもいい話なんですけど、一人でも「ああ、気になって仕方がない」と感じてくれる人が増えると溜飲も下がるというものです。私だけ気にしているのも馬鹿みたいですから。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

にわかな奴ほど語りたがる -- あるハッカー

読み込み中...