そんなわけで、得た DocumentFragment が body 要素を持っていたら、さらに body の子要素を DocumentFragment としてくくり出すようにした。くくり出す時に Range を使うのだが、これがちゃんと DocumentFragment にも作用するのか確証は持てない(DocumentFragment は Document のいわばサブクラスなので Range による操作も理屈の上では互換性があるはずなのだが、DocumentFragment に対する操作というのはけっこうどのブラウザも怪しい、あるいは怪しい時期があったのだ)。でもまあ、とりあえず動いているようだ。
function fixFragment (/*DocumentFragment*/f) {
var bodies = f.querySelectorAll('body');
if (bodies.length == 0) return f;
var r = document.createRange();
r.selectNodeContents(bodies[0]);
return r.cloneContents();
}
やっぱり一筋縄では行かない。例えば、赤福プラス ver.3 以降というのはいろいろな場面で XSLTProcessor が大回転するのだが。XSLTProcessor に食わせる xml は、そのソースが最初にページをロードした際は body.innerHTML、XHR で続きを読んだ際はふたばのサーバが返す html そのものと微妙に違う。なので、それぞれがほぼ同じものじゃないとちょっと困るのである。そして、Presto Opera と Chrome の innerHTML は期待通りの動作をする。つまり body.innerHTML を参照したとしても、元のソース文字列に出来るだけ同じものを返してくれる。
が、どういうわけか Firefox の場合は innerHTML は勝手に属性の定義順を書き換えたものを返してくれたりするようなのだ。どういうポリシーがあってそんなことをしでかしてくれるのかはよくわからない。html から中間 xml を生成する処理の内容はすなわち、ソース文字列を正規表現でパースするのである。したがって属性の定義順が不定だとか、パターンで表現できる範囲を超えられるとちょっと困るのである。
現役の web ブラウザが複数ある中で、それぞれが得手不得手があるのは自然なことである。しかしあくまで個人的な感想ですが、Presto Opera に関してそういう場面に出くわした場合、「おうおうお前はこれは苦手なのかうんうんかわいい奴め」という気分になるのだけれど(Presto Opera がもはや現役ではないという事情もあるのだが)、Firefox に対しては「てめーこの程度のこともできねーのかよ! 何年 web ブラウザやってんだアホッ!」と思う。あくまで個人的な感想です。
まず Kosian の HEAD に追従させるべくバックエンドの微調整。これは特に問題はない。めんどくさいのはフロントエンドで、フロントエンド側というのは開発の極々初期に html のレイアウトを Chrome や Firefox で確認したくらいで、それ以降の全ては Presto Opera でしか動かしていないのであった。特に、XSLTProcessor という素敵な処理系の動きが Chrome でも Opera と同様なのかどうか動かしてみないとまったくわからない。