agenda 2002-12(上旬) 別名「どこか」

DocumentFragmentの考察

公開
2002年12月6日

DOMのDocumentFragmentですが、今まで使おうと思ったことがありませんでした。使わなくても特に不自由しなかったからです。しかし、これを使わないと洒落にならない事例に出くわしました。

ケース:複数のノードの複製を繰り返しappendChildする

なんだか長くなったので別の文書にしました。

JavaScript有効かつDOM1 HTML対応なブラウザなら処理速度を体験できるようになっています。次の実装チェックボタンを押しても何も起らなかったり、falseとアラートされた場合、体験できません。

innerHTMLを利用した場合と比較していますが、innerHTMLはMSの独自拡張です。対応していない場合はエラーになります。ご了承ください。

DocumentFragmentの主な特徴

私が認識しているDocumentFragmentの主な特徴は、以下の通りです。

  1. 「軽量のDocumentオブジェクトである」とか言われていますが、私は嘘だと思います。継承しているのはNodeインターフェイスであり、createElementメソッド等は使えません。また、documentElement(ルート要素)に当たるものもありません。良く分からないと言われている原因は、この説明だと思います。
  2. appendChildやinsertBeforeのパラメータになった場合、その子ノードだけが追加されます。
  3. 複数の子ノードを持つことが出来ます。
  4. 以上より、たった一度のappendChild等で複数のノード(兄弟関係にあるものさえ)をごっそりと追加できることになります。
  5. 一度appendChild等のパラメータとして渡されると、そのDocumentFragmentのchildNodesは空っぽになります。何度も使いたい場合は、cloneNodeメソッドで複製してからということになります。
  6. 兄弟関係にあるような複数のノードを、繰り返しDOMツリーに追加するような場合に威力を発揮します。

DOM1 日本語訳に関する覚え書き

たとえば,DocumentFragment がもってよい子は1つだけであり,その子ノードは Text ノードであってもよい。

DOM1(コア) より

これは誤読される可能性が高いのではないでしょうか。DocumentFragmentは幾つでも子を持てます。そしてそれが重要な特徴です。原文はこちら:

For example, a DocumentFragment might have only one child and that child node could be a Text node.

Document Object Model (Core) Level 1 より

これは、DocumentFragmentの子が整形式のXMLでなくても良いという文脈で語られています。その例というわけです。私なら次のように訳します。

  • 例えば、DocumentFragmentの子は一つだけでも良く、それがTextノードであっても良い。

that child nodeを「それ」と訳しましたが、「その子ノード」と直訳すると、「その」が何なのか不明瞭になります。

MS版DOM1 HTMLの落とし穴

公開
2002年12月5日

この一年間、HTMLには悩まされ続けてきましたが、今回が一番嵌りました。次の糞HTMLの糞フラグメントをご覧下さい。

<p id="parent">
  <b id="me">
    <ul id="child">
      <li>list item</li>
    </ul>
  </b>
</p>

さて、この例のb要素(HTML B Element)へのポインタを幾つか作成したいと思います。親からアクセスするか、子からアクセスするかというニ通りの経路を考えます。

1.
var elmBviaParent = undefined;
var nlBSiblings = document.getElementById('parent').childNodes;
for(var i=0; i<nlBSiblings.length; i++)
{
  if(nlBSiblings.item(i).id == 'me')
  elmBviaParent = nlBSiblings.item(i);
}
2.
var elmBviaChild = document.getElementById('child').parentNode

この2つの変数が共に同一のb要素へのポインタになっている事を確かめる為、まずid属性値を比較してみます。

  • elmBviaParent.id === elmBviaChild.id

これは真です。共に「me」という文字列になっています。Internet Explorer6は、b要素の子としてul要素を持てるということでしょうか。

しかし、ここが怪しい部分です。そのまま比較してみましょう。

  • elmBviaParent == elmBviaChild

これも真です。まあ私は勝手に型変換されるのが恐いので、その必要がない限りは===で比較するようにしています。すると:

  • elmBviaParent === elmBviaChild

さあこれは偽です。falseです。両者がポイントしているのは違うオブジェクトであることが判明しました。==演算子で比較した場合は、型変換を通じて真だったのです。

両者の内のどちらかは、DOM1 HTMLのElement型では無いということでしょうか。これだからJScriptの==演算子は恐いのです。String型とNumber型以外ではどういう型変換が行われるのかはっきりしたことが分からないのです。特に恐いのは、効率の問題です。任意の2つのオブジェクトを比較した時、コード作成者には未知の数の型変換がトライされるのではないかと思うと、とてもじゃあないですが使う気になれません。因みにこれと似たような理由で、最近はwith文を使うのを止めました。

それはさておき、どちらが「なんちゃってElement型」なのかを確認する為、お馴染みの方法でもう一つのポインタを作成してみます。getElementByIdメソッドです。

3.
var elmB = document.getElementById('me')

1. 、2. 両者を、このelmBと比較してみます。

1-1.
elmBviaParent === elmB
2-1.
elmBviaChild === elmB

2-1. が偽です。b要素の子要素のul要素からparentNodeであるb要素を参照した場合には、Element型ではない何か未知の型「なんちゃってElement型」になっていると想像します。ではこの「なんちゃってElement型」は、DOM1 CoreのElementインターフェイスを実装しているのかといえば、しているようです。MS独自拡張のオマケの部分も含め、アトリビュートもメソッドも、全部実装しています。

IEならではの比較方法

そういうわけで、私はString、Number以外のオブジェクトを==演算子で比較したくないんです。何が行われているか良く分からないからです。では上の1. と 2. を比較して、型は兎も角同一の「要素」を参照しているかどうかを調べるにはどうすれば良いでしょうか。

Internet Explorerは、HTML文書の各要素にその登場順の番号を割り当てています。一意の識別子といえるでしょう。これはsourceIndexプロパティで参照できます。

elmBviaChild.sourceIndex === elmBviaParent.sourceIndex

そもそも

しかし、b要素の子にul要素を作るのはHTMLの文法違反であり、文法を守っていればこの問題は起りません。従って、責任はInternet Explorer側にはありません。

fub_net 日記(3)

公開
2002年12月4日

DOM弄りを楽しんでいます。過去の文書操作系のカスタムパネルは、DOM Inspectorをリッチにする形で統一しようと考えています(DOMといってもDOM1 HTML)。その他、危険な香りのするバグを発見したりしました。

妥当でないHTML文書のDOMツリー

ツリーの構築は:

  1. 表示しているHTML文書のルート要素(HTML要素)をパラメータとしたGUI操作用クラスのインスタンスを生成
  2. 記号をクリックした際、childNodesの各itemについて同様のインスタンスを生成

という形で行っています。一気にツリー全てを構築しようとすると、凄まじく時間がかかるからです。最初、これは私のJScriptコードに問題があるのかと思いましたが、何十回と繰り返されるappendChildメソッドによる描画速度の問題のようです。

しかしDOMツリーをカスタムパネル内に視覚化できたとしても、文書内のある要素が、DOMツリー上のどの位置にあるのかが分からなければ、これは完全に遊びに終ってしまうでしょう。fub_netの素晴らしい点は、アクティブタブ内に表示している文書のイベントを、カスタムパネル側で処理できることです。この特徴を利用すれば、「要素をクリックする」等のアクションを介して、DOMツリー上のその要素の位置をスタイルの変更等によって明示することが可能です。

要するにそこで躓いたわけです。わらい。

Ctrl + 右クリックでDOMツリーを展開し、クリックした要素の位置を明示するようにしました。真っ当なHTML文書であれば今のところ問題なく動作するのですが、b要素の子にul要素があるような「妥当でないHTML文書」の場合、その周辺で訳の分からないエラーが発生します。どうにもこうにも原因が分かりません。

危険な香りのするバグ

これは実はfub_netのバグではありません。IE6のバグです。簡単なブラウザクラッシャーを見つけました。

for(var i in alert){}

メソッドなら何でも良いのです。厄介なのは、typeof(alert)で"object"という文字列が返ってくることです。はて。"function"を期待していた私が馬鹿だったのでしょうか。

とほほのWWW入門が本に

公開
2002年12月2日

臨時企画。今日と明日の二本立てでお送りします。オチは私にも分かりそうで分かりません。

2002年12月2日

「とほほのWWW入門」が本になりました! 明日発売、とほほ。CGIはないの?

松風 - 今の言葉 より

とほほ。……って、何故です? 中身はまだ分からないじゃあないですか。例のW3Cの信者たちの努力が報われているかも知れません。

2002年12月3日

売られていませんでした。このためにわざわざ神田で降りるのも面倒だったので二軒くらいの書店しか見ていませんが。

というわけで結局オチはつきません。忘れて下さい。