宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
僕はXHTMLのルビ(小さな字で読み仮名をふったりするアレ)を使いたくてXHTML 1.1を選択してるんですが、過去にXHTML2で検討されてたl要素(パラグラフより細かい単位の「行」を示すための物)やiframeやなんかをどうしても埋め込みたくなって、しかしそのせいでバリデータでエラーが出てしまうのも嫌だったので、見よう見まねで頑張って独自の文書型宣言を書いてみたんですよ。いつやったのか忘れたけど、結構前に。
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
<!ENTITY % XLINK.xmlns.attrib "xmlns:xhtml2 CDATA #FIXED 'http://www.w3.org/2002/06/xhtml2'">
<!ENTITY % Inline.extra "| xhtml2:l | iframe">
<!ELEMENT xhtml2:l (#PCDATA|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|sub|sup|bdo|a|img|map|object|input|select|textarea|label|button|ruby|ins|del|script|noscript|xhtml2:l)*>
<!ATTLIST xhtml2:l
id ID #IMPLIED
class CDATA #IMPLIED
style CDATA #IMPLIED
title CDATA #IMPLIED>
<!ELEMENT iframe (#PCDATA|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|sub|sup|bdo|a|img|map|object|input|select|textarea|label|button|ruby|ins|del|script|noscript|xhtml2:l)*>
<!ATTLIST iframe
id ID #IMPLIED
class CDATA #IMPLIED
style CDATA #IMPLIED
title CDATA #IMPLIED
longdesc CDATA #IMPLIED
src CDATA #IMPLIED
frameborder ( 1 | 0 ) '1'
marginwidth CDATA #IMPLIED
marginheight CDATA #IMPLIED
scrolling ( yes | no | auto ) 'auto'
height CDATA #IMPLIED
width CDATA #IMPLIED
>
]>
CGIを使ってIEにはこの文書型宣言を出さないようにしてますが、FirefoxとかChromeとかでトップページあたりを開いてソースを見れば、こういうのが頭にくっついてるのが分かると思います。
で、バリデータ的にはこれでvalidになったのでめでたしめでたしだったんですが、GeckoのDTDパーサ部分にバグがあるらしくて、この文書型宣言を正しく解釈してくれないんですよね。最後の]>
ではなくその前の>
の部分で文書型宣言が終わったものと見なされてしまうせいで、Firefoxでこのサイトのページを開くと、ページの頭に謎の]>
という文字列がくっついてしまう状態になってたのです。表示が崩れるのが嫌だったので、この]>
がテキストノードとしてページの頭に存在してる時は動的に削除するようなJavaScriptを書いて、長らくごまかしてました。
そしたら先日、W3CのHTML5のルビに関する議論の中で紹介されてたXHTMLルビサポートのページを見たという方(Leif Halvard Silliさん)がメールを下さいまして、以下のようなハックを使えばページの頭に謎の]>
が出てくる事を防げるよ、と教えてくれたんです。
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
<!ENTITY % XLINK.xmlns.attrib "xmlns:xhtml2 CDATA #FIXED 'http://www.w3.org/2002/06/xhtml2'">
<!ENTITY % Inline.extra "| xhtml2:l | iframe">
<!ELEMENT xhtml2:l (#PCDATA|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|sub|sup|bdo|a|img|map|object|input|select|textarea|label|button|ruby|ins|del|script|noscript|xhtml2:l)*>
<!ATTLIST xhtml2:l
id ID #IMPLIED
class CDATA #IMPLIED
style CDATA #IMPLIED
title CDATA #IMPLIED>
<!ELEMENT iframe (#PCDATA|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|sub|sup|bdo|a|img|map|object|input|select|textarea|label|button|ruby|ins|del|script|noscript|xhtml2:l)*>
<!ATTLIST iframe
id ID #IMPLIED
class CDATA #IMPLIED
style CDATA #IMPLIED
title CDATA #IMPLIED
longdesc CDATA #IMPLIED
src CDATA #IMPLIED
frameborder ( 1 | 0 ) '1'
marginwidth CDATA #IMPLIED
marginheight CDATA #IMPLIED
scrolling ( yes | no | auto ) 'auto'
height CDATA #IMPLIED
width CDATA #IMPLIED
>
<?parser-hack ><!-- ?>
]>
<!--><?!-->
強調箇所がそのハック。処理命令(PHPのコード片を埋め込んだりするのに使うのと同じ奴)の記法でコメントとして解釈できる文字列を埋め込んで、問題の部分を無視させるという物のようです。バリデータに通しても、これでもvalidです。素晴らしいです。
同じような事をやってる酔狂な人がもしいたら役立てて欲しいと思ったので、氏に許可を得てエントリにさせて頂きました。Thanks a lot, Leif!
何故これがvalidなのかも考えてみよう。
<?parser-hack ><!-- ?>
><!--
という内容」を含んだ処理命令として解釈される。[
から]
までの間に登場しうる内容として処理命令も含まれている。そして、上記の箇所は一つの完結した処理命令である。よって、文書型宣言中に登場しても何ら問題ない。<!--><?!-->
><?!
という内容」を含んだコメントと解釈される。という具合で文法的には何も問題ないので、W3Cのバリデータはこれをvalidと判断する。きちんとXMLパーサを実装しているブラウザ上でも同様です。
一方、Geckoの解釈はどうか。これは「ソースを表示」での色分けを見るとよく分かる。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
Geckoはまず、この部分だけで完結した文書型宣言と認識する。「[
」で終わりと判断したのではなくて、その次の <!ENTITY
が来た時点で「あ、もう文書型宣言は終わってたのね」と見なしてるようだ。
<!ENTITY ~>
<!ELEMENT ~>
<!ATTLIST ~>
この辺はすべて、それぞれ別々の宣言として解釈されている。という事で、
]>
何もハックをしない場合はこの部分だけが取り残されてしまって、Gecko的にはこれが「XML的には不正だけどSGML的にはアリ」なテキストノードとして扱われて、ゴミとして表示されてしまうわけだ。
では、ハック有りの場合はどうなるか。
<?parser-hack ><!-- ?>
]>
<!--><?!-->
Geckoはこれを3つのノードとして解釈している。
<?parser-hack >
まずGeckoは、これを1つの処理命令と判断する。XMLの仕様では ?>
が来るまで処理命令の終わりにはならないんだけど、Geckoのパーサは >
で処理命令が終わったものと見なしてしまう。
<!-- ?>
]>
<!-->
これは当然1つのコメントになる。
<?!-->
最後、これも <?
から >
までで1つの処理命令と見なされる。
という事で、ハック有りの時はどの文字もテキストノードとして取り残されずに済むので、画面上は何もゴミが表示されずに済む。
こんなのよく考えるなー、と、読み解いてみて改めて感心しました。
の末尾に2020年11月30日時点の日本の首相のファミリーネーム(ローマ字で回答)を繋げて下さい。例えば「noda」なら、「2010-03-17_parser-hack.trackbacknoda」です。これは機械的なトラックバックスパムを防止するための措置です。
writeback message: Ready to post a comment.